diff --git a/packages/@core-js/src/BatteryAPI/BatteryGenerated.ts b/packages/@core-js/src/BatteryAPI/BatteryGenerated.ts
index 02ee15352..23d039035 100644
--- a/packages/@core-js/src/BatteryAPI/BatteryGenerated.ts
+++ b/packages/@core-js/src/BatteryAPI/BatteryGenerated.ts
@@ -21,6 +21,11 @@ export interface Status {
}
export interface Config {
+ /**
+ * with zero balance it is possible to transfer some jettons (stablecoins, jusdt, etc) to this address to refill the balance. Such transfers would be paid by Battery Service.
+ * @example "0:07331e629e39d006d86a8cc7659c10a97c671f7535dc8b7f251a1a944dda348e"
+ */
+ fund_receiver: string;
/**
* when building a message to transfer an NFT or Jetton, use this address to send excess funds back to Battery Service.
* @example "0:da6b1b6663a0e4d18cc8574ccd9db5296e367dd9324706f3bbd9eb1cd2caf0bf"
@@ -31,6 +36,11 @@ export interface Config {
export interface Balance {
/** @example "10.250" */
balance: string;
+ /**
+ * reserved amount in units (TON/USD)
+ * @example "0.3"
+ */
+ reserved: string;
/** @example "usd" */
units: BalanceUnitsEnum;
}
diff --git a/packages/@core-js/src/service/contractService.ts b/packages/@core-js/src/service/contractService.ts
index dd1d47ea0..b9522cdf5 100644
--- a/packages/@core-js/src/service/contractService.ts
+++ b/packages/@core-js/src/service/contractService.ts
@@ -11,6 +11,7 @@ import nacl from 'tweetnacl';
export enum OpCodes {
JETTON_TRANSFER = 0xf8a7ea5,
NFT_TRANSFER = 0x5fcc3d14,
+ STONFI_SWAP = 0x25938561,
}
export enum WalletVersion {
diff --git a/packages/@core-js/src/service/transactionService.ts b/packages/@core-js/src/service/transactionService.ts
index 2762b95bc..5ee4dbdc3 100644
--- a/packages/@core-js/src/service/transactionService.ts
+++ b/packages/@core-js/src/service/transactionService.ts
@@ -33,7 +33,7 @@ export function tonAddress(address: AnyAddress) {
}
export class TransactionService {
- private static TTL = 5 * 60;
+ public static TTL = 5 * 60;
private static getTimeout() {
return Math.floor(Date.now() / 1e3) + TransactionService.TTL;
@@ -104,6 +104,21 @@ export class TransactionService {
let builder = beginCell();
switch (opCode) {
+ case OpCodes.STONFI_SWAP:
+ builder = builder
+ .storeUint(OpCodes.STONFI_SWAP, 32)
+ .storeAddress(slice.loadAddress())
+ .storeCoins(slice.loadCoins())
+ .storeAddress(slice.loadAddress());
+
+ if (slice.loadBoolean()) {
+ slice.loadAddress();
+ }
+
+ return builder
+ .storeBit(1)
+ .storeAddress(Address.parse(customExcessesAccount))
+ .endCell();
case OpCodes.NFT_TRANSFER:
builder = builder
.storeUint(OpCodes.NFT_TRANSFER, 32)
@@ -130,7 +145,11 @@ export class TransactionService {
slice.loadMaybeAddress();
while (slice.remainingRefs) {
- builder = builder.storeRef(slice.loadRef());
+ const forwardCell = slice.loadRef();
+ // recursively rebuild forward payloads
+ builder = builder.storeRef(
+ this.rebuildBodyWithCustomExcessesAccount(forwardCell, customExcessesAccount),
+ );
}
return builder
diff --git a/packages/@core-js/src/utils/AmountFormatter/AmountFormatter.ts b/packages/@core-js/src/utils/AmountFormatter/AmountFormatter.ts
index a985e378f..60b517363 100644
--- a/packages/@core-js/src/utils/AmountFormatter/AmountFormatter.ts
+++ b/packages/@core-js/src/utils/AmountFormatter/AmountFormatter.ts
@@ -21,6 +21,8 @@ export type AmountFormatOptions = {
ignoreZeroTruncate?: boolean;
absolute?: boolean;
withPositivePrefix?: boolean;
+ // Truncate decimals. Required for backward compatibility
+ forceRespectDecimalPlaces?: boolean;
};
export type AmountFormatNanoOptions = AmountFormatOptions & {
@@ -144,7 +146,10 @@ export class AmountFormatter {
};
// truncate decimals 1.00 -> 1
- if (!options.ignoreZeroTruncate && bn.isLessThan('1000')) {
+ if (
+ options.forceRespectDecimalPlaces ||
+ (!options.ignoreZeroTruncate && bn.isLessThan('1000'))
+ ) {
bn = bn.decimalPlaces(decimals, BigNumber.ROUND_DOWN);
return bn.toFormat(formatConf);
}
diff --git a/packages/mobile/android/app/build.gradle b/packages/mobile/android/app/build.gradle
index 22aeaee46..8c0ffa385 100644
--- a/packages/mobile/android/app/build.gradle
+++ b/packages/mobile/android/app/build.gradle
@@ -92,7 +92,7 @@ android {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 433
- versionName "4.2.0"
+ versionName "4.3.0"
missingDimensionStrategy 'react-native-camera', 'general'
missingDimensionStrategy 'store', 'play'
}
diff --git a/packages/mobile/ios/ton_keeper.xcodeproj/project.pbxproj b/packages/mobile/ios/ton_keeper.xcodeproj/project.pbxproj
index f3ca23162..ed578fecd 100644
--- a/packages/mobile/ios/ton_keeper.xcodeproj/project.pbxproj
+++ b/packages/mobile/ios/ton_keeper.xcodeproj/project.pbxproj
@@ -1056,7 +1056,7 @@
outputFileListPaths = (
);
outputPaths = (
- $SRCROOT/$PROJECT_NAME/Resources/Generated/R.generated.swift,
+ "$SRCROOT/$PROJECT_NAME/Resources/Generated/R.generated.swift",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
@@ -1298,7 +1298,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
- MARKETING_VERSION = 4.2.0;
+ MARKETING_VERSION = 4.3.0;
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
@@ -1332,7 +1332,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
- MARKETING_VERSION = 4.2.0;
+ MARKETING_VERSION = 4.3.0;
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
diff --git a/packages/mobile/src/blockchain/wallet.ts b/packages/mobile/src/blockchain/wallet.ts
index c90a63b81..4c57219d9 100644
--- a/packages/mobile/src/blockchain/wallet.ts
+++ b/packages/mobile/src/blockchain/wallet.ts
@@ -26,7 +26,11 @@ import {
import { tk } from '$wallet';
import { Address, Cell, internal } from '@ton/core';
-import { emulateBoc, sendBoc } from '@tonkeeper/shared/utils/blockchain';
+import {
+ NetworkOverloadedError,
+ emulateBoc,
+ sendBoc,
+} from '@tonkeeper/shared/utils/blockchain';
import { OperationEnum, TonAPI, TypeEnum } from '@tonkeeper/core/src/TonAPI';
import { setBalanceForEmulation } from '@tonkeeper/shared/utils/wallet';
import { WalletNetwork } from '$wallet/WalletTypes';
@@ -34,6 +38,7 @@ import { createTonApiInstance } from '$wallet/utils';
import { config } from '$config';
import { toNano } from '$utils';
import { BatterySupportedTransaction } from '$wallet/managers/BatteryManager';
+import { compareAddresses } from '$utils/address';
const TonWeb = require('tonweb');
@@ -324,9 +329,15 @@ export class TonWallet {
private async calcFee(
boc: string,
params?,
- withRelayer = true,
+ withRelayer = false,
+ forceRelayer = false,
): Promise<[BigNumber, boolean]> {
- const { emulateResult, battery } = await emulateBoc(boc, params, withRelayer);
+ const { emulateResult, battery } = await emulateBoc(
+ boc,
+ params,
+ withRelayer,
+ forceRelayer,
+ );
return [new BigNumber(emulateResult.event.extra).multipliedBy(-1), battery];
}
@@ -423,6 +434,7 @@ export class TonWallet {
tk.wallet.battery.state.data.supportedTransactions[
BatterySupportedTransaction.Jetton
],
+ compareAddresses(address, tk.wallet.battery.fundReceiver),
);
return [Ton.fromNano(feeNano.toString()), isBattery];
@@ -469,7 +481,7 @@ export class TonWallet {
}
const excessesAccount = sendWithBattery
- ? await tk.wallet.battery.getExcessesAccount()
+ ? tk.wallet.battery.excessesAccount
: tk.wallet.address.ton.raw;
const boc = this.createJettonTransfer({
@@ -493,6 +505,7 @@ export class TonWallet {
tk.wallet.battery.state.data.supportedTransactions[
BatterySupportedTransaction.Jetton
],
+ compareAddresses(address, tk.wallet.battery.fundReceiver),
);
feeNano = fee;
isBattery = battery;
@@ -518,6 +531,9 @@ export class TonWallet {
try {
await sendBoc(boc, isBattery);
} catch (e) {
+ if (e instanceof NetworkOverloadedError) {
+ throw e;
+ }
if (!store.getState().main.isTimeSynced) {
throw new Error('wrong_time');
}
@@ -625,9 +641,7 @@ export class TonWallet {
? AddressFormatter.isBounceable(address)
: false,
});
-
const [feeNano, isBattery] = await this.calcFee(boc);
-
return [Ton.fromNano(feeNano.toString()), isBattery];
}
@@ -730,6 +744,9 @@ export class TonWallet {
try {
await sendBoc(boc, false);
} catch (e) {
+ if (e instanceof NetworkOverloadedError) {
+ throw e;
+ }
if (!store.getState().main.isTimeSynced) {
throw new Error('wrong_time');
}
diff --git a/packages/mobile/src/components/ScanQRButton.tsx b/packages/mobile/src/components/ScanQRButton.tsx
deleted file mode 100644
index 07da2171d..000000000
--- a/packages/mobile/src/components/ScanQRButton.tsx
+++ /dev/null
@@ -1,68 +0,0 @@
-import React, { memo, useMemo } from 'react';
-import { Icon, TouchableOpacity } from '$uikit';
-import { Steezy } from '$styles';
-import { store } from '$store';
-import { openScanQR, openSend } from '$navigation';
-import { CryptoCurrencies } from '$shared/constants';
-import { DeeplinkOrigin, useDeeplinking } from '$libs/deeplinking';
-import { openRequireWalletModal } from '$core/ModalContainer/RequireWallet/RequireWallet';
-import { Address } from '@tonkeeper/core';
-
-export const ScanQRButton = memo(() => {
- const deeplinking = useDeeplinking();
-
- const hitSlop = useMemo(
- () => ({
- top: 26,
- bottom: 26,
- left: 26,
- right: 26,
- }),
- [],
- );
-
- const handlePressScanQR = React.useCallback(() => {
- if (store.getState().wallet.wallet) {
- openScanQR((address) => {
- if (Address.isValid(address)) {
- setTimeout(() => {
- openSend({ currency: CryptoCurrencies.Ton, address });
- }, 200);
-
- return true;
- }
-
- const resolver = deeplinking.getResolver(address, {
- delay: 200,
- origin: DeeplinkOrigin.QR_CODE,
- });
-
- if (resolver) {
- resolver();
- return true;
- }
-
- return false;
- });
- } else {
- openRequireWalletModal();
- }
- }, []);
-
- return (
-
-
-
- );
-});
-
-const styles = Steezy.create({
- container: {
- zIndex: 3,
- },
-});
diff --git a/packages/mobile/src/context/WalletContext.tsx b/packages/mobile/src/context/WalletContext.tsx
index 6e9d02742..c5ab86eba 100644
--- a/packages/mobile/src/context/WalletContext.tsx
+++ b/packages/mobile/src/context/WalletContext.tsx
@@ -14,6 +14,5 @@ export const WalletProvider = ({ children }: { children: React.ReactNode }) => {
return unsubscribe;
}, []);
-
return {children};
};
diff --git a/packages/mobile/src/core/Colectibles/Collectibles.tsx b/packages/mobile/src/core/Colectibles/Collectibles.tsx
new file mode 100644
index 000000000..7534a03a2
--- /dev/null
+++ b/packages/mobile/src/core/Colectibles/Collectibles.tsx
@@ -0,0 +1,59 @@
+import React, { memo, useMemo } from 'react';
+import { View } from '$uikit';
+import { NFTCardItem } from './NFTCardItem';
+import { Steezy } from '$styles';
+import { useWindowDimensions } from 'react-native';
+import { useApprovedNfts } from '$hooks/useApprovedNfts';
+import { Screen } from '@tonkeeper/uikit';
+import { t } from '@tonkeeper/shared/i18n';
+
+const mockupCardSize = {
+ width: 114,
+ height: 166,
+};
+
+const numColumn = 3;
+const heightRatio = mockupCardSize.height / mockupCardSize.width;
+
+export const Collectibles = memo(() => {
+ const nfts = useApprovedNfts();
+ const dimensions = useWindowDimensions();
+
+ const size = useMemo(() => {
+ const width = (dimensions.width - 48) / numColumn;
+ const height = width * heightRatio;
+
+ return { width, height };
+ }, [dimensions.width]);
+
+ return (
+
+
+ (
+
+
+
+ )}
+ />
+
+ );
+});
+
+const styles = Steezy.create({
+ collectiblesContainer: {
+ marginHorizontal: 16,
+ gap: 8,
+ },
+ nftElements: {
+ flexDirection: 'row',
+ flexWrap: 'wrap',
+ },
+ columnWrapper: {
+ gap: 8,
+ },
+});
diff --git a/packages/mobile/src/core/Colectibles/NFTCardItem.style.ts b/packages/mobile/src/core/Colectibles/NFTCardItem.style.ts
new file mode 100644
index 000000000..4e2b00d2c
--- /dev/null
+++ b/packages/mobile/src/core/Colectibles/NFTCardItem.style.ts
@@ -0,0 +1,75 @@
+import styled, { RADIUS } from '$styled';
+import { ns } from '$utils';
+import FastImage from 'react-native-fast-image';
+import { Highlight } from '$uikit';
+import { Dimensions } from 'react-native';
+
+const deviceWidth = Dimensions.get('window').width;
+export const NUM_OF_COLUMNS = Math.trunc(Math.max(2, Math.min(deviceWidth / 171, 3)));
+const availableWidth = NUM_OF_COLUMNS === 2 ? (deviceWidth - ns(48)) / 2 : 171; // Padding and margin between NFTs
+
+export const Wrap = styled.View<{ withMargin: boolean }>`
+ width: ${availableWidth}px;
+ margin-right: ${({ withMargin }) => (withMargin ? ns(16) : 0)}px;
+ margin-bottom: ${ns(16)}px;
+`;
+
+export const Background = styled.View`
+ background: ${({ theme }) => theme.colors.backgroundSecondary};
+ border-radius: ${ns(RADIUS.normal)}px;
+ position: absolute;
+ z-index: 0;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+`;
+
+export const Pressable = styled(Highlight)`
+ border-radius: ${ns(RADIUS.normal)}px;
+`;
+
+export const Image = styled(FastImage).attrs({
+ resizeMode: 'cover',
+})`
+ position: relative;
+ z-index: 2;
+ width: 100%;
+ height: ${ns(171)}px;
+ border-top-left-radius: ${ns(RADIUS.normal)}px;
+ border-top-right-radius: ${ns(RADIUS.normal)}px;
+ background: ${({ theme }) => theme.colors.backgroundTertiary};
+`;
+
+export const Badges = styled.View`
+ position: absolute;
+ bottom: ${8}px;
+ right: ${8}px;
+ flex-direction: row;
+ align-items: center;
+`;
+
+export const FireBadge = styled.View`
+ position: absolute;
+ bottom: ${0}px;
+ right: ${0}px;
+ flex-direction: row;
+ align-items: center;
+`;
+
+export const OnSaleBadge = styled.View`
+ position: absolute;
+ top: ${0}px;
+ right: ${0}px;
+ flex-direction: row;
+ align-items: center;
+`;
+
+export const AppearanceBadge = styled.View`
+ width: ${ns(32)}px;
+ height: ${ns(32)}px;
+ border-radius: ${ns(32 / 2)}px;
+ background: ${({ theme }) => theme.colors.backgroundSecondary};
+ align-items: center;
+ justify-content: center;
+`;
diff --git a/packages/mobile/src/tabs/Wallet/NFTCardItem.tsx b/packages/mobile/src/core/Colectibles/NFTCardItem.tsx
similarity index 97%
rename from packages/mobile/src/tabs/Wallet/NFTCardItem.tsx
rename to packages/mobile/src/core/Colectibles/NFTCardItem.tsx
index df9c7c968..adade1249 100644
--- a/packages/mobile/src/tabs/Wallet/NFTCardItem.tsx
+++ b/packages/mobile/src/core/Colectibles/NFTCardItem.tsx
@@ -6,7 +6,7 @@ import { checkIsTonDiamondsNFT } from '$utils';
import { useFlags } from '$utils/flags';
import _ from 'lodash';
import React, { memo, useCallback, useMemo } from 'react';
-import * as S from '../../core/NFTs/NFTItem/NFTItem.style';
+import * as S from './NFTCardItem.style';
import { useExpiringDomains } from '$store/zustand/domains/useExpiringDomains';
import { AnimationDirection, HideableAmount } from '$core/HideableAmount/HideableAmount';
import { HideableImage } from '$core/HideableAmount/HideableImage';
@@ -100,8 +100,6 @@ const styles = Steezy.create(({ colors, corners }) => ({
container: {
position: 'relative',
flex: 1,
- marginHorizontal: 4,
- marginBottom: 8,
backgroundColor: colors.backgroundContent,
borderRadius: corners.medium,
overflow: 'hidden',
diff --git a/packages/mobile/src/core/CustomizeWallet/CustomizeWallet.tsx b/packages/mobile/src/core/CustomizeWallet/CustomizeWallet.tsx
index a4c9029e5..a12a629a1 100644
--- a/packages/mobile/src/core/CustomizeWallet/CustomizeWallet.tsx
+++ b/packages/mobile/src/core/CustomizeWallet/CustomizeWallet.tsx
@@ -14,6 +14,7 @@ import {
TouchableOpacity,
View,
WalletColor,
+ WalletIcon,
getWalletColorHex,
isAndroid,
ns,
@@ -29,7 +30,7 @@ import React, {
useRef,
useState,
} from 'react';
-import { Keyboard, LayoutChangeEvent, Text as RNText } from 'react-native';
+import { Keyboard, LayoutChangeEvent } from 'react-native';
import { ScrollView } from 'react-native-gesture-handler';
import Animated, { useAnimatedStyle, withTiming } from 'react-native-reanimated';
import { EmojiPicker } from './EmojiPicker';
@@ -163,7 +164,7 @@ export const CustomizeWallet: FC = memo((props) => {
{ backgroundColor: getWalletColorHex(selectedColor) },
]}
>
- {emoji}
+
diff --git a/packages/mobile/src/core/CustomizeWallet/EmojiPicker/EmojiPicker.tsx b/packages/mobile/src/core/CustomizeWallet/EmojiPicker/EmojiPicker.tsx
index 0d90f00f2..8a14f9842 100644
--- a/packages/mobile/src/core/CustomizeWallet/EmojiPicker/EmojiPicker.tsx
+++ b/packages/mobile/src/core/CustomizeWallet/EmojiPicker/EmojiPicker.tsx
@@ -1,8 +1,9 @@
import { isAndroid } from '$utils';
import { FlashList } from '@shopify/flash-list';
-import { Steezy, View, ns } from '@tonkeeper/uikit';
+import { Steezy, View, WalletIcon, ns } from '@tonkeeper/uikit';
+import { WALLET_ICONS } from '@tonkeeper/uikit/src/utils/walletIcons';
import React, { memo, useCallback } from 'react';
-import { Text, TouchableOpacity } from 'react-native';
+import { TouchableOpacity } from 'react-native';
import LinearGradient from 'react-native-linear-gradient';
interface Emoji {
@@ -12,6 +13,11 @@ interface Emoji {
const emojis: Emoji[] = require('./emojis.json');
+const items: Emoji[] = [
+ ...WALLET_ICONS.map((value) => ({ emoji: value, name: value })),
+ ...emojis,
+];
+
interface EmojiPickerProps {
onChange: (value: string) => void;
}
@@ -22,7 +28,7 @@ export const EmojiPicker: React.FC = memo(({ onChange }) => {
return (
onChange(item.emoji)}>
- {item.emoji}
+
);
@@ -33,7 +39,7 @@ export const EmojiPicker: React.FC = memo(({ onChange }) => {
return (
item.name}
renderItem={renderEmoji}
diff --git a/packages/mobile/src/core/HideableAmount/ShowBalance.tsx b/packages/mobile/src/core/HideableAmount/ShowBalance.tsx
index abea7aa99..b6890c3c1 100644
--- a/packages/mobile/src/core/HideableAmount/ShowBalance.tsx
+++ b/packages/mobile/src/core/HideableAmount/ShowBalance.tsx
@@ -57,6 +57,6 @@ const styles = Steezy.create(({ colors }) => ({
borderRadius: 100,
},
stars: {
- paddingTop: 5.5,
+ paddingTop: 8,
},
}));
diff --git a/packages/mobile/src/core/InscriptionScreen.tsx b/packages/mobile/src/core/InscriptionScreen.tsx
index ab0a3ec8e..5ffe31f52 100644
--- a/packages/mobile/src/core/InscriptionScreen.tsx
+++ b/packages/mobile/src/core/InscriptionScreen.tsx
@@ -1,6 +1,7 @@
import { useTonInscription } from '@tonkeeper/shared/query/hooks/useTonInscription';
import { useParams } from '@tonkeeper/router/src/imperative';
import {
+ ActionButtons,
DEFAULT_TOKEN_LOGO,
IconButton,
IconButtonList,
@@ -62,21 +63,24 @@ export const InscriptionScreen = memo(() => {
-
-
- {!wallet.isWatchOnly ? (
-
- ) : null}
-
-
+
+
@@ -86,7 +90,7 @@ export const InscriptionScreen = memo(() => {
const styles = Steezy.create(({ colors }) => ({
tokenContainer: {
paddingTop: 16,
- paddingBottom: 28,
+ paddingBottom: 24,
flexDirection: 'row',
justifyContent: 'space-between',
marginHorizontal: 28,
@@ -96,14 +100,6 @@ const styles = Steezy.create(({ colors }) => ({
height: 64,
borderRadius: 64 / 2,
},
- buttons: {
- borderTopWidth: 1,
- borderBottomWidth: 1,
- borderTopColor: colors.backgroundContent,
- borderBottomColor: colors.backgroundContent,
- paddingTop: 16,
- paddingBottom: 12,
- },
tokenText: {
paddingTop: 2,
},
diff --git a/packages/mobile/src/core/Jetton/Jetton.style.ts b/packages/mobile/src/core/Jetton/Jetton.style.ts
index e244d6eb5..06077fa30 100644
--- a/packages/mobile/src/core/Jetton/Jetton.style.ts
+++ b/packages/mobile/src/core/Jetton/Jetton.style.ts
@@ -11,7 +11,6 @@ export const Wrap = styled.View`
export const ChartWrap = styled.View`
margin-bottom: ${ns(24.5)}px;
- margin-top: 18px;
`;
export const HeaderWrap = styled.View`
@@ -44,7 +43,7 @@ export const FlexRow = styled.View`
flex-direction: row;
justify-content: space-between;
margin-top: ${ns(16)}px;
- margin-bottom: ${ns(28)}px;
+ padding-horizontal: ${ns(12)}px;
`;
export const JettonAmountWrapper = styled.View`
diff --git a/packages/mobile/src/core/Jetton/Jetton.tsx b/packages/mobile/src/core/Jetton/Jetton.tsx
index 28aac5c49..99a1b5c5d 100644
--- a/packages/mobile/src/core/Jetton/Jetton.tsx
+++ b/packages/mobile/src/core/Jetton/Jetton.tsx
@@ -17,7 +17,15 @@ import { Events, JettonVerification, SendAnalyticsFrom } from '$store/models';
import { t } from '@tonkeeper/shared/i18n';
import { trackEvent } from '$utils/stats';
import { Address } from '@tonkeeper/core';
-import { Icon, Screen, Spacer, Steezy, TouchableOpacity, View } from '@tonkeeper/uikit';
+import {
+ ActionButtons,
+ Icon,
+ Screen,
+ Spacer,
+ Steezy,
+ TouchableOpacity,
+ View,
+} from '@tonkeeper/uikit';
import { useJettonActivityList } from '@tonkeeper/shared/query/hooks/useJettonActivityList';
import { ActivityList } from '@tonkeeper/shared/components';
@@ -121,42 +129,37 @@ export const Jetton: React.FC = ({ route }) => {
>
) : null}
- {jettonPrice.formatted.fiat ? (
- <>
-
-
- {t('jetton_price')} {jettonPrice.formatted.fiat}
-
- >
- ) : null}
{jetton.metadata.image ? (
) : null}
-
-
- {!isWatchOnly ? (
-
- ) : null}
-
- {!isWatchOnly && showSwap && !flags.disable_swap ? (
- }
- title={t('wallet.swap_btn')}
- />
- ) : null}
-
-
+
+
+
{shouldShowChart && (
<>
@@ -177,7 +180,8 @@ export const Jetton: React.FC = ({ route }) => {
);
}, [
jetton,
- jettonPrice,
+ jettonPrice.formatted.totalFiat,
+ lockedJettonPrice.formatted.totalFiat,
isWatchOnly,
handleSend,
handleReceive,
@@ -185,6 +189,7 @@ export const Jetton: React.FC = ({ route }) => {
flags.disable_swap,
handlePressSwap,
shouldShowChart,
+ shouldExcludeChartPeriods,
fiatCurrency,
route.params.jettonAddress,
]);
@@ -214,7 +219,7 @@ export const Jetton: React.FC = ({ route }) => {
)
}
- title={jetton.metadata?.name || Address.toShort(jetton.jettonAddress)}
+ title={jetton.metadata?.symbol || Address.toShort(jetton.jettonAddress)}
rightContent={
{
- const tabBarHeight = useBottomTabBarHeight();
+ const insets = useSafeAreaInsets();
return (
@@ -17,7 +18,7 @@ export const FontLicense: React.FC = () => {
showsVerticalScrollIndicator={false}
contentContainerStyle={{
paddingHorizontal: ns(16),
- paddingBottom: tabBarHeight,
+ paddingBottom: insets.bottom + 16,
}}
scrollEventThrottle={16}
>
@@ -124,4 +125,4 @@ INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.
-`;
\ No newline at end of file
+`;
diff --git a/packages/mobile/src/core/LegalDocuments/LegalDocuments.tsx b/packages/mobile/src/core/LegalDocuments/LegalDocuments.tsx
index efd71caa2..948a500da 100644
--- a/packages/mobile/src/core/LegalDocuments/LegalDocuments.tsx
+++ b/packages/mobile/src/core/LegalDocuments/LegalDocuments.tsx
@@ -1,5 +1,4 @@
import React, { FC, useCallback, useMemo } from 'react';
-import { useBottomTabBarHeight } from '@react-navigation/bottom-tabs';
import Animated from 'react-native-reanimated';
import { Icon, NavBar, ScrollHandler, Text } from '$uikit';
import { ns } from '$utils';
@@ -7,9 +6,10 @@ import { CellSection, CellSectionItem } from '$shared/components';
import * as S from './LegalDocuments.style';
import { openDAppBrowser, openFontLicense } from '$navigation';
import { t } from '@tonkeeper/shared/i18n';
+import { useSafeAreaInsets } from 'react-native-safe-area-context';
export const LegalDocuments: FC = () => {
- const tabBarHeight = useBottomTabBarHeight();
+ const insets = useSafeAreaInsets();
const handleTerms = useCallback(() => {
openDAppBrowser('https://tonkeeper.com/terms');
@@ -36,7 +36,7 @@ export const LegalDocuments: FC = () => {
showsVerticalScrollIndicator={false}
contentContainerStyle={{
paddingHorizontal: ns(16),
- paddingBottom: tabBarHeight,
+ paddingBottom: insets.bottom + 16,
}}
scrollEventThrottle={16}
>
diff --git a/packages/mobile/src/core/Logs/Logs.tsx b/packages/mobile/src/core/Logs/Logs.tsx
index c94633a71..5e5a50ff6 100644
--- a/packages/mobile/src/core/Logs/Logs.tsx
+++ b/packages/mobile/src/core/Logs/Logs.tsx
@@ -1,5 +1,4 @@
import React, { FC, useCallback, useMemo } from 'react';
-import { useBottomTabBarHeight } from '@react-navigation/bottom-tabs';
import { useDispatch, useSelector } from 'react-redux';
import Clipboard from '@react-native-community/clipboard';
@@ -10,10 +9,11 @@ import { format, ns } from '$utils';
import { Toast } from '$store';
import { t } from '@tonkeeper/shared/i18n';
+import { useSafeAreaInsets } from 'react-native-safe-area-context';
export const Logs: FC = () => {
- const tabBarHeight = useBottomTabBarHeight();
const dispatch = useDispatch();
+ const insets = useSafeAreaInsets();
const { logs } = useSelector(mainSelector);
@@ -33,27 +33,24 @@ export const Logs: FC = () => {
];
}, [logs]);
- const handleItemPress = useCallback(
- (item) => {
- const payload = [
- `Screen: ${item.screen}`,
- `Time: ${item.time}`,
- `Message: ${item.message}`,
- `Stack: ${item.trace}`,
- ].join('\n');
+ const handleItemPress = useCallback((item) => {
+ const payload = [
+ `Screen: ${item.screen}`,
+ `Time: ${item.time}`,
+ `Message: ${item.message}`,
+ `Stack: ${item.trace}`,
+ ].join('\n');
- Clipboard.setString(payload);
- Toast.success(t('copied'));
- },
- [t, dispatch],
- );
+ Clipboard.setString(payload);
+ Toast.success(t('copied'));
+ }, []);
return (
Logs
{
diff --git a/packages/mobile/src/core/ModalContainer/CreateSubscription/CreateSubscription.style.ts b/packages/mobile/src/core/ModalContainer/CreateSubscription/CreateSubscription.style.ts
index 0a2a7d642..87d40e452 100644
--- a/packages/mobile/src/core/ModalContainer/CreateSubscription/CreateSubscription.style.ts
+++ b/packages/mobile/src/core/ModalContainer/CreateSubscription/CreateSubscription.style.ts
@@ -9,38 +9,19 @@ export const LoaderWrap = styled.View`
`;
export const Header = styled.View`
- flex-direction: row;
- padding: ${ns(0)}px ${ns(16)}px ${ns(32)}px;
+ align-items: center;
+ padding-top: ${ns(48)}px;
`;
export const MerchantPhoto = styled(FastImage).attrs({
resizeMode: 'cover',
})`
- width: ${ns(72)}px;
- height: ${ns(72)}px;
- border-radius: ${ns(72 / 2)}px;
+ width: ${ns(96)}px;
+ height: ${ns(96)}px;
+ border-radius: ${ns(96 / 2)}px;
background: ${({ theme }) => theme.colors.backgroundSecondary};
`;
-export const MerchantInfoWrap = styled.View`
- margin-left: ${ns(16)}px;
- flex: 1;
- align-items: flex-start;
-`;
-
-export const MerchantInfo = styled.View`
- height: ${ns(72)}px;
- justify-content: center;
-`;
-
-export const ProductNameWrapper = styled.View`
- margin-top: ${ns(2)}px;
-`;
-
-export const Content = styled.View`
- padding-horizontal: ${ns(16)}px;
-`;
-
export const ButtonWrap = styled.View`
margin-top: ${ns(16)}px;
flex: 0 0 auto;
diff --git a/packages/mobile/src/core/ModalContainer/CreateSubscription/CreateSubscription.tsx b/packages/mobile/src/core/ModalContainer/CreateSubscription/CreateSubscription.tsx
index 8f57058ef..9fa748ae4 100644
--- a/packages/mobile/src/core/ModalContainer/CreateSubscription/CreateSubscription.tsx
+++ b/packages/mobile/src/core/ModalContainer/CreateSubscription/CreateSubscription.tsx
@@ -1,19 +1,14 @@
-import React, { FC, useCallback, useEffect, useMemo, useRef, useState } from 'react';
+import React, { FC, useCallback, useEffect, useMemo, useState } from 'react';
import { Alert, Linking } from 'react-native';
import { useDispatch, useSelector } from 'react-redux';
import TonWeb from 'tonweb';
import { getUnixTime } from 'date-fns';
import { CreateSubscriptionProps } from './CreateSubscription.interface';
import * as S from './CreateSubscription.style';
-import { Button, Icon, Loader, Text } from '$uikit';
-import { List } from '@tonkeeper/uikit';
+import { Button, Loader, Text } from '$uikit';
+import { List, Spacer } from '@tonkeeper/uikit';
import { SubscriptionModel } from '$store/models';
-import {
- format,
- formatSubscriptionPeriod,
- toLocaleNumber,
- triggerNotificationSuccess,
-} from '$utils';
+import { format, formatSubscriptionPeriod, toLocaleNumber } from '$utils';
import { subscriptionsActions } from '$store/subscriptions';
import { CryptoCurrencies, Decimals } from '$shared/constants';
import { formatCryptoCurrency } from '$utils/currency';
@@ -29,6 +24,7 @@ import { SheetActions, useNavigation } from '@tonkeeper/router';
import { Modal, View } from '@tonkeeper/uikit';
import { config } from '$config';
import { tk } from '$wallet';
+import { ActionFooter, useActionFooter } from '../NFTOperations/NFTOperationFooter';
export const CreateSubscription: FC = ({
invoiceId = null,
@@ -43,15 +39,13 @@ export const CreateSubscription: FC = ({
const { amount: balance } = useWalletInfo();
const [isLoading, setLoading] = useState(!isEdit);
- const [failed, setFailed] = useState(0);
const [fee, setFee] = useState(
passedFee || (subscription && subscription.fee ? subscription.fee : '~'),
);
const [info, setInfo] = useState(subscription);
- const [isSending, setSending] = useState(false);
- const [isSuccess, setSuccess] = useState(false);
const [totalMoreThanBalance, setTotalMoreThanBalance] = React.useState(false);
- const closeTimer = useRef(null);
+
+ const { footerRef, onConfirm } = useActionFooter();
useEffect(() => {
if (fee !== '~') {
@@ -61,39 +55,6 @@ export const CreateSubscription: FC = ({
}
}, [info, balance, fee]);
- useEffect(() => {
- if (isSuccess) {
- triggerNotificationSuccess();
- closeTimer.current = setTimeout(() => {
- nav.goBack();
-
- if (!isEdit && !subscription) {
- const returnUrl = info!.userReturnUrl;
- Alert.alert(
- t('subscription_back_to_merchant_title'),
- t('subscription_back_to_merchant_caption'),
- [
- {
- text: t('cancel'),
- style: 'cancel',
- },
- {
- text: t('subscription_back_to_merchant_button'),
- onPress: () => {
- Linking.openURL(returnUrl).catch((err) => {
- console.log(err);
- });
- },
- },
- ],
- );
- }
- }, 2500);
- }
-
- return () => closeTimer.current && clearTimeout(closeTimer.current);
- }, [isSuccess]);
-
const loadInfo = useCallback(() => {
const host = config.get('subscriptionsHost', tk.wallet.isTestnet);
network
@@ -110,7 +71,7 @@ export const CreateSubscription: FC = ({
Toast.fail(e.message);
nav.goBack();
});
- }, [invoiceId]);
+ }, [invoiceId, nav]);
useEffect(() => {
if (!isEdit) {
@@ -169,22 +130,47 @@ export const CreateSubscription: FC = ({
return format((info.chargedAt + info.intervalSec) * 1000, 'EEE, MMM d');
}, [info]);
- const handleSubscribe = useCallback(() => {
- setSending(true);
- dispatch(
- subscriptionsActions.subscribe({
- subscription: info!,
- onDone: () => {
- setSuccess(true);
- },
- onFail: () => {
- setSending(false);
- },
- }),
- );
- }, [dispatch, info]);
+ const handleSubscribe = useCallback(async () => {
+ onConfirm(async ({ startLoading }) => {
+ startLoading();
+
+ await new Promise((resolve, reject) => {
+ dispatch(
+ subscriptionsActions.subscribe({
+ subscription: info!,
+ onDone: () => {
+ resolve();
+
+ if (!isEdit && !subscription) {
+ const returnUrl = info!.userReturnUrl;
+ Alert.alert(
+ t('subscription_back_to_merchant_title'),
+ t('subscription_back_to_merchant_caption'),
+ [
+ {
+ text: t('cancel'),
+ style: 'cancel',
+ },
+ {
+ text: t('subscription_back_to_merchant_button'),
+ onPress: () => {
+ Linking.openURL(returnUrl).catch((err) => {
+ console.log(err);
+ });
+ },
+ },
+ ],
+ );
+ }
+ },
+ onFail: reject,
+ }),
+ );
+ });
+ })();
+ }, [dispatch, info, isEdit, onConfirm, subscription]);
- const handleUnsubscribe = useCallback(() => {
+ const handleUnsubscribe = useCallback(async () => {
Alert.alert(
t('subscription_cancel_alert_title'),
t('subscription_cancel_alert_caption', {
@@ -199,23 +185,24 @@ export const CreateSubscription: FC = ({
text: t('subscription_cancel_alert_submit_btn'),
style: 'destructive',
onPress: () => {
- setSending(true);
- dispatch(
- subscriptionsActions.unsubscribe({
- subscription: info!,
- onDone: () => {
- setSuccess(true);
- },
- onFail: () => {
- setSending(false);
- },
- }),
- );
+ onConfirm(async ({ startLoading }) => {
+ startLoading();
+
+ await new Promise((resolve, reject) => {
+ dispatch(
+ subscriptionsActions.unsubscribe({
+ subscription: info!,
+ onDone: resolve,
+ onFail: reject,
+ }),
+ );
+ });
+ })();
},
},
],
);
- }, [dispatch, info, nextBill, t]);
+ }, [dispatch, info, nextBill, onConfirm]);
const isButtonShown = useMemo(() => {
if (!info) {
@@ -227,7 +214,7 @@ export const CreateSubscription: FC = ({
}
return info.status === 'new' || info.isActive;
- }, [info, isEdit, isSuccess, isSending]);
+ }, [info, isEdit]);
const handleOpenMerchant = useCallback(() => {
Linking.openURL(info!.returnUrl).catch((err) => {
@@ -236,45 +223,32 @@ export const CreateSubscription: FC = ({
}, [info]);
function renderButton() {
- if (isSuccess) {
- return (
-
-
-
-
- {t('subscription_sent')}
-
-
-
- );
- }
-
- if (isSending) {
- return (
-
-
-
- );
- }
-
if (isEdit || info?.isActive) {
return (
-
+
);
}
return (
-
+ redirectToActivity={false}
+ ref={footerRef}
+ />
);
}
@@ -287,37 +261,33 @@ export const CreateSubscription: FC = ({
);
}
- // ToDo: Сделать верстку, когда будет дизайн
- if (failed) {
- return Failed;
- }
-
return (
<>
-
-
-
- {info.merchantName}
-
-
-
- {info.productName}
-
-
-
- {info.status === 'created' && (
+
+
+ {info.merchantName}
+
+
+
+ {info.productName}
+
+ {info.status === 'created' && (
+ <>
+
- )}
-
+ >
+ )}
+
= ({
/>
)}
-
- {isButtonShown && {renderButton()}}
-
+ {isButtonShown && renderButton()}
>
);
}
return (
-
+
{renderContent()}
diff --git a/packages/mobile/src/core/ModalContainer/InsufficientFunds/InsufficientFunds.tsx b/packages/mobile/src/core/ModalContainer/InsufficientFunds/InsufficientFunds.tsx
index 80b68734a..7693153c8 100644
--- a/packages/mobile/src/core/ModalContainer/InsufficientFunds/InsufficientFunds.tsx
+++ b/packages/mobile/src/core/ModalContainer/InsufficientFunds/InsufficientFunds.tsx
@@ -1,6 +1,6 @@
import React, { memo, useCallback, useMemo } from 'react';
import { t } from '@tonkeeper/shared/i18n';
-import { Modal, Spacer } from '@tonkeeper/uikit';
+import { Modal, Spacer, WalletIcon } from '@tonkeeper/uikit';
import { openExploreTab, openRefillBatteryModal } from '$navigation';
import { SheetActions, useNavigation } from '@tonkeeper/router';
import { Button, Icon, Text } from '$uikit';
@@ -14,6 +14,7 @@ import { useBatteryBalance } from '@tonkeeper/shared/query/hooks/useBatteryBalan
import { config } from '$config';
import { Wallet } from '$wallet/Wallet';
import { AmountFormatter } from '@tonkeeper/core';
+import { tk } from '$wallet';
export interface InsufficientFundsParams {
/**
@@ -35,6 +36,7 @@ export interface InsufficientFundsParams {
stakingFee?: string;
fee?: string;
isStakingDeposit?: boolean;
+ walletIdentifier?: string;
}
export const InsufficientFundsModal = memo((props) => {
@@ -46,6 +48,7 @@ export const InsufficientFundsModal = memo((props) => {
stakingFee,
fee,
isStakingDeposit,
+ walletIdentifier,
} = props;
const { balance: batteryBalance } = useBatteryBalance();
const nav = useNavigation();
@@ -120,6 +123,8 @@ export const InsufficientFundsModal = memo((props) => {
);
}, [currency, fee, formattedAmount, formattedBalance, isStakingDeposit, stakingFee]);
+ const wallet = walletIdentifier ? tk.wallets.get(walletIdentifier)! : tk.wallet;
+
return (
@@ -128,7 +133,15 @@ export const InsufficientFundsModal = memo((props) => {
- {t('txActions.signRaw.insufficientFunds.title')}
+ {tk.wallets.size > 1 ? (
+ <>
+ {t('txActions.signRaw.insufficientFunds.title_multiwallet')}{' '}
+ {' '}
+ {wallet.config.name}
+ >
+ ) : (
+ t('txActions.signRaw.insufficientFunds.title')
+ )}
{content}
diff --git a/packages/mobile/src/core/ModalContainer/NFTOperations/Modals/SignRawModal.tsx b/packages/mobile/src/core/ModalContainer/NFTOperations/Modals/SignRawModal.tsx
index 071b32479..6552d6b32 100644
--- a/packages/mobile/src/core/ModalContainer/NFTOperations/Modals/SignRawModal.tsx
+++ b/packages/mobile/src/core/ModalContainer/NFTOperations/Modals/SignRawModal.tsx
@@ -6,7 +6,19 @@ import { calculateMessageTransferAmount, delay } from '$utils';
import { debugLog } from '$utils/debugLog';
import { t } from '@tonkeeper/shared/i18n';
import { Toast } from '$store';
-import { List, Modal, Spacer, Steezy, Text, View } from '@tonkeeper/uikit';
+import {
+ List,
+ Modal,
+ Spacer,
+ Steezy,
+ Text,
+ View,
+ WalletIcon,
+ isAndroid,
+ Icon,
+ ListItemContent,
+ TouchableOpacity,
+} from '@tonkeeper/uikit';
import { push } from '$navigation/imperative';
import { SheetActions, useNavigation } from '@tonkeeper/router';
import {
@@ -29,7 +41,7 @@ import { formatValue, getActionTitle } from '@tonkeeper/shared/utils/signRaw';
import { Buffer } from 'buffer';
import { trackEvent } from '$utils/stats';
import { Events, SendAnalyticsFrom } from '$store/models';
-import { getWalletSeqno } from '@tonkeeper/shared/utils/wallet';
+import { getWalletSeqno, setBalanceForEmulation } from '@tonkeeper/shared/utils/wallet';
import { useWalletCurrency } from '@tonkeeper/shared/hooks';
import {
ActionAmountType,
@@ -43,6 +55,9 @@ import { TokenDetailsParams } from '../../../../components/TokenDetails/TokenDet
import { ModalStackRouteNames } from '$navigation';
import { CanceledActionError } from '$core/Send/steps/ConfirmStep/ActionErrors';
import { emulateBoc, sendBoc } from '@tonkeeper/shared/utils/blockchain';
+import { openAboutRiskAmountModal } from '@tonkeeper/shared/modals/AboutRiskAmountModal';
+import { toNano } from '@ton/core';
+import BigNumber from 'bignumber.js';
interface SignRawModalProps {
consequences?: MessageConsequences;
@@ -103,7 +118,7 @@ export const SignRawModal = memo((props) => {
const boc = TransactionService.createTransfer(contract, {
messages: TransactionService.parseSignRawMessages(
params.messages,
- isBattery ? await tk.wallet.battery.getExcessesAccount() : undefined,
+ isBattery ? tk.wallet.battery.excessesAccount : undefined,
),
seqno: await getWalletSeqno(wallet),
sendMode: 3,
@@ -164,8 +179,7 @@ export const SignRawModal = memo((props) => {
return {
isNegative: formatter.isNegative(extra),
value: formatter.format(extra, {
- ignoreZeroTruncate: true,
- withoutTruncate: true,
+ decimals: 4,
postfix: 'TON',
absolute: true,
}),
@@ -208,6 +222,27 @@ export const SignRawModal = memo((props) => {
return undefined;
};
+ const totalRiskedAmount = useMemo(() => {
+ if (consequences?.risk) {
+ return wallet.compareWithTotal(consequences.risk.ton, consequences.risk.jettons);
+ }
+ }, [consequences, wallet]);
+
+ const totalAmountTitle = useMemo(() => {
+ if (totalRiskedAmount) {
+ return (
+ t('confirmSendModal.total_risk', {
+ totalAmount: formatter.format(totalRiskedAmount.totalFiat, {
+ currency: fiatCurrency,
+ }),
+ }) +
+ (consequences?.risk.nfts.length > 0
+ ? ` + ${consequences?.risk.nfts.length} NFT`
+ : '')
+ );
+ }
+ }, [consequences?.risk.nfts.length, fiatCurrency, totalRiskedAmount]);
+
return (
((props) => {
{t('confirmSendModal.wallet')}
-
- {wallet.config.emoji}
-
+
{wallet.config.name}
@@ -257,32 +294,59 @@ export const SignRawModal = memo((props) => {
/>
))}
+
+
+
+ }
+ subvalue={extra.fiat}
+ subtitle={isBattery && t('confirmSendModal.will_be_paid_with_battery')}
+ title={
+ extra.isNegative
+ ? t('confirmSendModal.network_fee')
+ : t('confirmSendModal.refund')
+ }
+ value={`≈ ${extra.value}`}
+ />
-
-
- {extra.isNegative
- ? t('confirmSendModal.network_fee')
- : t('confirmSendModal.refund')}
-
-
- ≈ {extra.value} · {extra.fiat}
-
-
- {isBattery && (
-
-
- {t('confirmSendModal.will_be_paid_with_battery')}
-
-
- )}
+ {totalRiskedAmount ? (
+ <>
+
+
+ {totalAmountTitle}
+
+
+ openAboutRiskAmountModal(
+ totalAmountTitle!,
+ consequences?.risk.nfts.length > 0,
+ )
+ }
+ >
+
+
+
+
+ >
+ ) : null}
);
@@ -325,16 +389,20 @@ export const openSignRawModal = async (
secretKey: Buffer.alloc(64),
});
+ const totalAmount = calculateMessageTransferAmount(params.messages);
const { emulateResult, battery } = await emulateBoc(
boc,
- undefined,
+ [
+ setBalanceForEmulation(
+ new BigNumber(totalAmount).plus(toNano('2').toString()).toString(),
+ ),
+ ], // Emulate with higher balance to calculate fair amount to send
options.experimentalWithBattery,
);
consequences = emulateResult;
isBattery = battery;
if (!isBattery) {
- const totalAmount = calculateMessageTransferAmount(params.messages);
const checkResult = await checkIsInsufficient(totalAmount, wallet);
if (checkResult.insufficient) {
Toast.hide();
@@ -342,6 +410,7 @@ export const openSignRawModal = async (
return openInsufficientFundsModal({
totalAmount,
balance: checkResult.balance,
+ walletIdentifier,
});
}
}
@@ -382,7 +451,15 @@ export const openSignRawModal = async (
}
};
-const styles = Steezy.create({
+const styles = Steezy.create(({ colors }) => ({
+ icon: {
+ width: 44,
+ height: 44,
+ borderRadius: 44 / 2,
+ alignItems: 'center',
+ justifyContent: 'center',
+ backgroundColor: colors.backgroundContentTint,
+ },
feeContainer: {
paddingHorizontal: 32,
paddingTop: 12,
@@ -392,6 +469,7 @@ const styles = Steezy.create({
subtitleContainer: {
flexDirection: 'row',
gap: 4,
+ alignItems: 'center',
},
withBatteryContainer: {
paddingHorizontal: 32,
@@ -399,4 +477,14 @@ const styles = Steezy.create({
actionsList: {
marginBottom: 0,
},
-});
+ emoji: {
+ fontSize: isAndroid ? 17 : 20,
+ marginTop: isAndroid ? -1 : 1,
+ },
+ totalAmountContainer: {
+ gap: 4,
+ flexDirection: 'row',
+ justifyContent: 'center',
+ alignItems: 'center',
+ },
+}));
diff --git a/packages/mobile/src/core/ModalContainer/NFTOperations/NFTOperationFooter.tsx b/packages/mobile/src/core/ModalContainer/NFTOperations/NFTOperationFooter.tsx
index 936bab614..5a0bf6b9f 100644
--- a/packages/mobile/src/core/ModalContainer/NFTOperations/NFTOperationFooter.tsx
+++ b/packages/mobile/src/core/ModalContainer/NFTOperations/NFTOperationFooter.tsx
@@ -19,6 +19,8 @@ import {
import { tk } from '$wallet';
import { TabsStackRouteNames } from '$navigation';
import { Wallet } from '$wallet/Wallet';
+import { NetworkOverloadedError } from '@tonkeeper/shared/utils/blockchain';
+import { SlideButton, Steezy } from '@tonkeeper/uikit';
enum States {
INITIAL,
@@ -95,7 +97,11 @@ export const useActionFooter = (wallet?: Wallet) => {
(wallet ?? tk.wallet).activityList.reload();
});
} catch (error) {
- if (error instanceof DismissedActionError) {
+ if (error instanceof NetworkOverloadedError) {
+ ref.current?.setError(error.message);
+ await delay(3500);
+ ref.current?.setState(States.INITIAL);
+ } else if (error instanceof DismissedActionError) {
ref.current?.setState(States.ERROR);
await delay(1750);
ref.current?.setState(States.INITIAL);
@@ -131,10 +137,12 @@ interface ActionFooterProps {
responseOptions?: TxResponseOptions;
withCloseButton?: boolean;
confirmTitle?: string;
+ secondary?: boolean;
onPressConfirm: () => Promise;
onCloseModal?: () => void;
disabled?: boolean;
redirectToActivity?: boolean;
+ withSlider?: boolean;
}
export const ActionFooter = React.forwardRef(
@@ -193,22 +201,33 @@ export const ActionFooter = React.forwardRef
isVisible={state === States.INITIAL}
entranceAnimation={false}
>
-
- {withCloseButton ? (
- <>
- closeModal(false)}>
- {t('cancel')}
-
-
- >
- ) : null}
- props.onPressConfirm()}
- >
- {props.confirmTitle ?? t('nft_confirm_operation')}
-
-
+ {props.withSlider ? (
+
+ props.onPressConfirm()}
+ text={t('nft_operation_slide_to_confirm')}
+ />
+
+ ) : (
+
+ {withCloseButton ? (
+ <>
+ closeModal(false)}>
+ {t('cancel')}
+
+
+ >
+ ) : null}
+ props.onPressConfirm()}
+ mode={props.secondary ? 'secondary' : 'primary'}
+ >
+ {props.confirmTitle ?? t('nft_confirm_operation')}
+
+
+ )}
},
);
+const styles = Steezy.create({
+ slideContainer: {
+ paddingHorizontal: 16,
+ paddingVertical: 16,
+ },
+});
+
export const NFTOperationFooter = ActionFooter;
diff --git a/packages/mobile/src/core/ModalContainer/NFTOperations/NFTOperations.ts b/packages/mobile/src/core/ModalContainer/NFTOperations/NFTOperations.ts
index 422469074..8c9e4d655 100644
--- a/packages/mobile/src/core/ModalContainer/NFTOperations/NFTOperations.ts
+++ b/packages/mobile/src/core/ModalContainer/NFTOperations/NFTOperations.ts
@@ -15,6 +15,7 @@ import { Ton } from '$libs/Ton';
import { Configuration, NFTApi } from '@tonkeeper/core/src/legacy';
import { tk } from '$wallet';
import { config } from '$config';
+import { sendBoc } from '@tonkeeper/shared/utils/blockchain';
const { NftItem } = TonWeb.token.nft;
@@ -171,10 +172,7 @@ export class NFTOperations {
const queryMsg = await methods.getQuery();
const boc = Base64.encodeBytes(await queryMsg.toBoc(false));
- await tk.wallet.tonapi.blockchain.sendBlockchainMessage(
- { boc },
- { format: 'text' },
- );
+ await sendBoc(boc, false);
onDone?.(boc);
},
@@ -277,10 +275,7 @@ export class NFTOperations {
const queryMsg = await transfer.getQuery();
const boc = Base64.encodeBytes(await queryMsg.toBoc(false));
- await tk.wallet.tonapi.blockchain.sendBlockchainMessage(
- { boc },
- { format: 'text' },
- );
+ await sendBoc(boc, false);
},
};
}
diff --git a/packages/mobile/src/core/NFTSend/NFTSend.tsx b/packages/mobile/src/core/NFTSend/NFTSend.tsx
index 79ae333fc..ba62d509b 100644
--- a/packages/mobile/src/core/NFTSend/NFTSend.tsx
+++ b/packages/mobile/src/core/NFTSend/NFTSend.tsx
@@ -291,7 +291,7 @@ export const NFTSend: FC = (props) => {
throw new CanceledActionError();
}
- const excessesAccount = isBattery && (await wallet.battery.getExcessesAccount());
+ const excessesAccount = isBattery && tk.wallet.battery.excessesAccount;
const nftTransferMessages = [
internal({
diff --git a/packages/mobile/src/core/NFTSend/steps/ConfirmStep/ConfirmStep.style.ts b/packages/mobile/src/core/NFTSend/steps/ConfirmStep/ConfirmStep.style.ts
index 485ca184c..39e786921 100644
--- a/packages/mobile/src/core/NFTSend/steps/ConfirmStep/ConfirmStep.style.ts
+++ b/packages/mobile/src/core/NFTSend/steps/ConfirmStep/ConfirmStep.style.ts
@@ -98,3 +98,9 @@ export const Icon = styled(FastImage).attrs({
export const ItemSkeleton = styled.View`
align-self: flex-end;
`;
+
+export const WalletNameRow = styled.View`
+ flex-direction: row;
+ align-items: center;
+ justify-content: flex-end;
+`;
diff --git a/packages/mobile/src/core/NFTSend/steps/ConfirmStep/ConfirmStep.tsx b/packages/mobile/src/core/NFTSend/steps/ConfirmStep/ConfirmStep.tsx
index ba0a1e898..b8eff459b 100644
--- a/packages/mobile/src/core/NFTSend/steps/ConfirmStep/ConfirmStep.tsx
+++ b/packages/mobile/src/core/NFTSend/steps/ConfirmStep/ConfirmStep.tsx
@@ -21,6 +21,7 @@ import { truncateDecimal } from '$utils';
import { BatteryState } from '@tonkeeper/shared/utils/battery';
import { useBatteryState } from '@tonkeeper/shared/query/hooks/useBatteryState';
import { tk } from '$wallet';
+import { Steezy, WalletIcon, isAndroid } from '@tonkeeper/uikit';
interface Props extends StepComponentProps {
recipient: SendRecipient | null;
@@ -106,9 +107,15 @@ const ConfirmStepComponent: FC = (props) => {
{t('send_screen_steps.comfirm.wallet')}
-
- {tk.wallet.config.emoji} {tk.wallet.config.name}
-
+
+
+
+ {tk.wallet.config.name}
+
@@ -219,3 +226,10 @@ const ConfirmStepComponent: FC = (props) => {
};
export const ConfirmStep = memo(ConfirmStepComponent);
+
+const styles = Steezy.create({
+ emoji: {
+ fontSize: isAndroid ? 17 : 20,
+ marginTop: isAndroid ? -1 : 1,
+ },
+});
diff --git a/packages/mobile/src/core/NFTs/AboutCollection/AboutCollection.tsx b/packages/mobile/src/core/NFTs/AboutCollection/AboutCollection.tsx
deleted file mode 100644
index 5dd123444..000000000
--- a/packages/mobile/src/core/NFTs/AboutCollection/AboutCollection.tsx
+++ /dev/null
@@ -1,5 +0,0 @@
-import React from 'react';
-
-export const AboutCollection: React.FC = ({ name, }) => {
-
-}
diff --git a/packages/mobile/src/core/NFTs/MarketplaceBanner/MarketplaceBanner.interface.ts b/packages/mobile/src/core/NFTs/MarketplaceBanner/MarketplaceBanner.interface.ts
deleted file mode 100644
index b2490242d..000000000
--- a/packages/mobile/src/core/NFTs/MarketplaceBanner/MarketplaceBanner.interface.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export interface MarketplaceBannerProps {
- onButtonPress: () => void;
-}
diff --git a/packages/mobile/src/core/NFTs/MarketplaceBanner/MarketplaceBanner.style.ts b/packages/mobile/src/core/NFTs/MarketplaceBanner/MarketplaceBanner.style.ts
deleted file mode 100644
index fd2fbcbf1..000000000
--- a/packages/mobile/src/core/NFTs/MarketplaceBanner/MarketplaceBanner.style.ts
+++ /dev/null
@@ -1,63 +0,0 @@
-import styled, { RADIUS } from '$styled';
-import { hNs, nfs, ns } from '$utils';
-import FastImage from 'react-native-fast-image';
-
-export const Wrap = styled.View`
- justify-content: space-between;
- flex: 1;
- margin: 0 ${hNs(32)}px 0 ${hNs(32)}px;
-`;
-
-export const ButtonWrap = styled.View`
- align-items: center;
- justify-content: center;
- flex: 0 0 auto;
-`;
-
-export const Background = styled.View`
- background: ${({ theme }) => theme.colors.backgroundSecondary};
- border-radius: ${ns(RADIUS.normal)}px;
- position: absolute;
- z-index: 1;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
-`;
-
-export const ImagesFirstContainer = styled.View`
- flex-direction: row;
- justify-content: center;
- margin-bottom: ${ns(8)}px;
-`;
-
-export const ImagesSecondContainer = styled.View`
- flex-direction: row;
- justify-content: center;
- margin-bottom: ${ns(32)}px;
-`;
-
-export const Cont = styled.View`
- z-index: 2;
- flex: 1;
- align-items: center;
- justify-content: center;
-`;
-
-export const TextCont = styled.View`
- align-items: center;
-`;
-
-export const TitleWrapper = styled.View`
- margin-bottom: ${ns(8)}px;
-`;
-
-export const Image = styled(FastImage).attrs({
- resizeMode: 'cover',
- priority: FastImage.priority.high,
-})<{ isLast?: boolean }>`
- width: ${ns(56)}px;
- height: ${hNs(56)}px;
- border-radius: ${ns(12)}px;
- margin-right: ${({ isLast }) => ns(isLast ? 0 : 8)}px;
-`;
diff --git a/packages/mobile/src/core/NFTs/MarketplaceBanner/MarketplaceBanner.tsx b/packages/mobile/src/core/NFTs/MarketplaceBanner/MarketplaceBanner.tsx
deleted file mode 100644
index e765d0d1f..000000000
--- a/packages/mobile/src/core/NFTs/MarketplaceBanner/MarketplaceBanner.tsx
+++ /dev/null
@@ -1,89 +0,0 @@
-import React, { useContext } from 'react';
-import * as S from './MarketplaceBanner.style';
-import { t } from '@tonkeeper/shared/i18n';
-import {Button, ScrollPositionContext, Text} from '$uikit';
-import { MarketplaceBannerProps } from './MarketplaceBanner.interface';
-import { useBottomTabBarHeight } from '@react-navigation/bottom-tabs';
-import { ns } from '$utils';
-import { useFocusEffect } from '@react-navigation/native';
-import { useSafeAreaInsets } from 'react-native-safe-area-context';
-import { useFlags } from '$utils/flags';
-
-const images = {
- 1: [
- require('$assets/marketplaceBannerNFTs/1.png'),
- require('$assets/marketplaceBannerNFTs/2.png'),
- require('$assets/marketplaceBannerNFTs/3.png'),
- ],
- 2: [
- require('$assets/marketplaceBannerNFTs/4.png'),
- require('$assets/marketplaceBannerNFTs/5.png'),
- require('$assets/marketplaceBannerNFTs/6.png'),
- require('$assets/marketplaceBannerNFTs/7.png'),
- ],
-};
-
-export const MarketplaceBanner: React.FC = ({
- onButtonPress,
-}) => {
- const flags = useFlags(['disable_nft_markets']);
-
- const tabBarHeight = useBottomTabBarHeight();
- const { changeEnd } = useContext(ScrollPositionContext);
- const { top: topInset } = useSafeAreaInsets();
-
- useFocusEffect(
- React.useCallback(() => {
- changeEnd(true);
- }, [changeEnd]),
- );
-
- return (
-
-
-
- {images[1].map((img, idx, arr) => (
-
- ))}
-
-
- {images[2].map((img, idx, arr) => (
-
- ))}
-
-
-
-
- {t('nft_marketplace_banner_title')}
-
-
-
- {
- flags.disable_nft_markets
- ? t('disable_nft_marketplace_banner_description')
- : t('nft_marketplace_banner_description')
- }
-
-
- {!flags.disable_nft_markets && (
-
- )}
-
-
- );
-};
diff --git a/packages/mobile/src/core/NFTs/NFTItem/NFTItem.interface.ts b/packages/mobile/src/core/NFTs/NFTItem/NFTItem.interface.ts
deleted file mode 100644
index 8dfa15c74..000000000
--- a/packages/mobile/src/core/NFTs/NFTItem/NFTItem.interface.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-import { NFTModel } from '$store/models';
-
-export interface NFTItemProps {
- isLastInRow: boolean;
- item: NFTModel;
-};
diff --git a/packages/mobile/src/core/NFTs/NFTItem/NFTItem.style.ts b/packages/mobile/src/core/NFTs/NFTItem/NFTItem.style.ts
deleted file mode 100644
index 526c2731c..000000000
--- a/packages/mobile/src/core/NFTs/NFTItem/NFTItem.style.ts
+++ /dev/null
@@ -1,150 +0,0 @@
-import styled, { RADIUS } from '$styled';
-import { ns } from '$utils';
-import FastImage from 'react-native-fast-image';
-import { Highlight } from '$uikit';
-import { Dimensions, StyleSheet } from 'react-native';
-
-const deviceWidth = Dimensions.get('window').width;
-export const NUM_OF_COLUMNS = Math.trunc(Math.max(2, Math.min(deviceWidth / 171, 3)));
-const availableWidth = NUM_OF_COLUMNS === 2 ? (deviceWidth - ns(48)) / 2 : 171; // Padding and margin between NFTs
-
-export const Wrap = styled.View<{ withMargin: boolean }>`
- width: ${availableWidth}px;
- margin-right: ${({ withMargin }) => (withMargin ? ns(16) : 0)}px;
- margin-bottom: ${ns(16)}px;
-`;
-
-export const Background = styled.View`
- background: ${({ theme }) => theme.colors.backgroundSecondary};
- border-radius: ${ns(RADIUS.normal)}px;
- position: absolute;
- z-index: 0;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
-`;
-
-export const TextWrap = styled.View`
- z-index: 2;
- padding: ${ns(10)}px ${ns(16)}px ${ns(12)}px ${ns(16)}px;
-`;
-
-export const Pressable = styled(Highlight)`
- border-radius: ${ns(RADIUS.normal)}px;
-`;
-
-export const Image = styled(FastImage).attrs({
- resizeMode: 'cover',
-})`
- position: relative;
- z-index: 2;
- width: 100%;
- height: ${ns(171)}px;
- border-top-left-radius: ${ns(RADIUS.normal)}px;
- border-top-right-radius: ${ns(RADIUS.normal)}px;
- background: ${({ theme }) => theme.colors.backgroundTertiary};
-`;
-
-export const DNSBackground = styled.View`
- position: relative;
- z-index: 2;
- width: 100%;
- height: ${ns(171)}px;
- border-top-left-radius: ${ns(RADIUS.normal)}px;
- border-top-right-radius: ${ns(RADIUS.normal)}px;
- background: ${({ theme }) => theme.colors.accentPrimary};
- padding-vertical: ${ns(16)}px;
- padding-horizontal: ${ns(20)}px;
-`;
-
-export const SmallImage = styled(FastImage).attrs({
- resizeMode: 'cover',
-})`
- z-index: 2;
- flex: 1;
- width: 100%;
- height: 100%;
- /* height: ${ns(114)}px; */
- border-top-left-radius: ${ns(RADIUS.normal)}px;
- border-top-right-radius: ${ns(RADIUS.normal)}px;
- background: ${({ theme }) => theme.colors.backgroundTertiary};
-`;
-
-export const SmallDNSBackground = styled.View`
- position: relative;
- z-index: 2;
- width: 100%;
- height: ${ns(114)}px;
- border-top-left-radius: ${ns(RADIUS.normal)}px;
- border-top-right-radius: ${ns(RADIUS.normal)}px;
- background: ${({ theme }) => theme.colors.accentPrimary};
- padding-vertical: ${ns(16)}px;
- padding-horizontal: ${ns(20)}px;
-`;
-
-export const Badges = styled.View`
- position: absolute;
- bottom: ${8}px;
- right: ${8}px;
- flex-direction: row;
- align-items: center;
-`;
-
-export const FireBadge = styled.View`
- position: absolute;
- bottom: ${0}px;
- right: ${0}px;
- flex-direction: row;
- align-items: center;
-`;
-
-export const OnSaleBadge = styled.View`
- position: absolute;
- top: ${0}px;
- right: ${0}px;
- flex-direction: row;
- align-items: center;
-`;
-
-export const OnSaleBadgeIcon = styled.Image.attrs({
- source: require('$assets/sale_badge_32.png'),
-})`
- width: ${ns(32)}px;
- height: ${ns(32)}px;
-`;
-
-export const AppearanceBadge = styled.View`
- width: ${ns(32)}px;
- height: ${ns(32)}px;
- border-radius: ${ns(32 / 2)}px;
- background: ${({ theme }) => theme.colors.backgroundSecondary};
- align-items: center;
- justify-content: center;
-`;
-
-export const DNSBadge = styled.View`
- width: ${ns(32)}px;
- height: ${ns(32)}px;
- border-radius: ${ns(32 / 2)}px;
- background: rgba(255, 255, 255, 0.2);
- align-items: center;
- justify-content: center;
-`;
-
-export const textStyles = StyleSheet.create({
- domainText: {
- fontWeight: '700',
- fontSize: 20,
- lineHeight: 26,
- },
- domainZoneText: {
- opacity: 0.72,
- },
-});
-
-export const CollectionNameWrap = styled.View<{ withIcon?: boolean }>`
- flex-direction: row;
- align-items: center;
- padding-right: ${({ withIcon }) => (!withIcon ? 0 : ns(12))}px;
-`;
diff --git a/packages/mobile/src/core/NFTs/NFTItem/NFTItem.tsx b/packages/mobile/src/core/NFTs/NFTItem/NFTItem.tsx
deleted file mode 100644
index a2f4322d2..000000000
--- a/packages/mobile/src/core/NFTs/NFTItem/NFTItem.tsx
+++ /dev/null
@@ -1,98 +0,0 @@
-import React, { useCallback, useMemo } from 'react';
-import { NFTItemProps } from '$core/NFTs/NFTItem/NFTItem.interface';
-import * as S from './NFTItem.style';
-import { openNFT } from '$navigation';
-import { checkIsTonDiamondsNFT } from '$utils';
-import _ from 'lodash';
-import { Icon, Text } from '$uikit';
-import { t } from '@tonkeeper/shared/i18n';
-import { useFlags } from '$utils/flags';
-import { Address, DNS, KnownTLDs } from '@tonkeeper/core';
-
-export const NFTItem: React.FC = ({ item, isLastInRow }) => {
- const flags = useFlags(['disable_apperance']);
-
- const isTonDiamondsNft = checkIsTonDiamondsNFT(item);
- const isOnSale = useMemo(() => !!item.sale, [item.sale]);
-
- const isTG = DNS.getTLD(item.dns || item.name) === KnownTLDs.TELEGRAM;
- const isDNS = !!item.dns && !isTG;
-
- // eslint-disable-next-line react-hooks/exhaustive-deps
- const handleOpenNftItem = useCallback(
- _.throttle(() => openNFT({ currency: item.currency, address: item.address }), 1000),
- [item],
- );
-
- const title = useMemo(() => {
- if (isDNS) {
- return item.dns;
- }
-
- return item.name || Address.toShort(item.address);
- }, [isDNS, item.dns, item.name, item.address]);
-
- const renderPicture = () => {
- if (isDNS) {
- return (
-
-
- {item.dns?.replace('.ton', '')}
-
-
- {'.ton'}
-
- {isOnSale ? : null}
-
-
-
-
-
-
- );
- }
-
- return (
-
- {isOnSale ? : null}
-
- {isTonDiamondsNft && !flags.disable_apperance ? (
-
-
-
- ) : null}
-
-
- );
- };
-
- return (
-
-
-
- {renderPicture()}
-
-
- {title}
-
-
-
- {isDNS
- ? 'TON DNS'
- : item?.collection
- ? item.collection.name
- : t('nft_single_nft')}
-
- {item.isApproved && (
-
- )}
-
-
-
-
- );
-};
diff --git a/packages/mobile/src/core/Notifications/Notification.tsx b/packages/mobile/src/core/Notifications/Notification.tsx
index 15afa856b..033f94db8 100644
--- a/packages/mobile/src/core/Notifications/Notification.tsx
+++ b/packages/mobile/src/core/Notifications/Notification.tsx
@@ -192,7 +192,7 @@ export const Notification: React.FC = (props) => {
}, [props.closeOtherSwipeable]);
return (
-
+
({
listStyle: {
marginBottom: 0,
},
- containerStyle: {
- marginBottom: 8,
- },
leftContentStyle: {
alignItems: 'flex-start',
alignSelf: 'flex-start',
diff --git a/packages/mobile/src/core/Notifications/Notifications.tsx b/packages/mobile/src/core/Notifications/Notifications.tsx
index 54676f1e7..a03c561e9 100644
--- a/packages/mobile/src/core/Notifications/Notifications.tsx
+++ b/packages/mobile/src/core/Notifications/Notifications.tsx
@@ -9,19 +9,19 @@ import {
View,
} from '$uikit';
import { ns } from '$utils';
-import { useBottomTabBarHeight } from '@react-navigation/bottom-tabs';
import { CellSection } from '$shared/components';
import { t } from '@tonkeeper/shared/i18n';
import { useConnectedAppsList } from '$store';
import { Steezy } from '$styles';
import { SwitchDAppNotifications } from '$core/Notifications/SwitchDAppNotifications';
import { useNotificationsSwitch } from '$hooks/useNotificationsSwitch';
+import { useSafeAreaInsets } from 'react-native-safe-area-context';
export const Notifications: React.FC = () => {
- const tabBarHeight = useBottomTabBarHeight();
const connectedApps = useConnectedAppsList();
const { isSubscribed, isDenied, openSettings, toggleNotifications } =
useNotificationsSwitch();
+ const insets = useSafeAreaInsets();
return (
@@ -29,7 +29,7 @@ export const Notifications: React.FC = () => {
{isDenied && (
diff --git a/packages/mobile/src/core/Notifications/NotificationsActivity.tsx b/packages/mobile/src/core/Notifications/NotificationsActivity.tsx
index b557a98da..0d79fb960 100644
--- a/packages/mobile/src/core/Notifications/NotificationsActivity.tsx
+++ b/packages/mobile/src/core/Notifications/NotificationsActivity.tsx
@@ -1,5 +1,5 @@
import React, { useCallback, useEffect, useMemo, useRef } from 'react';
-import { Button, Icon, Screen, Spacer, Text, View } from '$uikit';
+import { Button, Icon, Spacer, Text, View } from '$uikit';
import { Notification } from '$core/Notifications/Notification';
import { Steezy } from '$styles';
import { openNotifications } from '$navigation';
@@ -8,6 +8,7 @@ import { INotification, useDAppsNotifications } from '$store';
import { FlashList } from '@shopify/flash-list';
import { LayoutAnimation } from 'react-native';
import { useBottomTabBarHeight } from '@react-navigation/bottom-tabs';
+import { Screen } from '@tonkeeper/uikit';
export enum ActivityListItem {
Notification = 'Notification',
@@ -51,7 +52,6 @@ export const NotificationsActivity: React.FC = () => {
const list = useRef | null>(null);
const closeOtherSwipeable = useRef void)>(null);
const lastSwipeableId = useRef(null);
- const tabBarHeight = useBottomTabBarHeight();
const handleOpenNotificationSettings = useCallback(() => {
openNotifications();
@@ -137,10 +137,10 @@ export const NotificationsActivity: React.FC = () => {
) : (
item.id}
renderItem={renderNotificationsItem}
- contentContainerStyle={{ paddingBottom: tabBarHeight + 8 }}
data={flashListData}
ListEmptyComponent={ListEmpty}
/>
@@ -154,6 +154,9 @@ const styles = Steezy.create({
marginVertical: 14,
marginHorizontal: 16,
},
+ gap8: {
+ gap: 8,
+ },
emptyContainer: {
paddingHorizontal: 32,
flex: 1,
diff --git a/packages/mobile/src/core/Security/Security.tsx b/packages/mobile/src/core/Security/Security.tsx
index 922d72fa9..8e704f244 100644
--- a/packages/mobile/src/core/Security/Security.tsx
+++ b/packages/mobile/src/core/Security/Security.tsx
@@ -1,6 +1,5 @@
import React, { FC, useCallback } from 'react';
import Animated from 'react-native-reanimated';
-import { useBottomTabBarHeight } from '@react-navigation/bottom-tabs';
import Clipboard from '@react-native-community/clipboard';
import * as S from './Security.style';
@@ -14,9 +13,10 @@ import { useBiometrySettings, useWallet } from '@tonkeeper/shared/hooks';
import { useNavigation } from '@tonkeeper/router';
import { vault } from '$wallet';
import { Haptics, Switch } from '@tonkeeper/uikit';
+import { useSafeAreaInsets } from 'react-native-safe-area-context';
export const Security: FC = () => {
- const tabBarHeight = useBottomTabBarHeight();
+ const insets = useSafeAreaInsets();
const wallet = useWallet();
const nav = useNavigation();
@@ -93,7 +93,7 @@ export const Security: FC = () => {
showsVerticalScrollIndicator={false}
contentContainerStyle={{
paddingHorizontal: ns(16),
- paddingBottom: tabBarHeight,
+ paddingBottom: insets.bottom + 16,
}}
scrollEventThrottle={16}
>
diff --git a/packages/mobile/src/core/Send/Send.tsx b/packages/mobile/src/core/Send/Send.tsx
index fab73db27..a95c7797f 100644
--- a/packages/mobile/src/core/Send/Send.tsx
+++ b/packages/mobile/src/core/Send/Send.tsx
@@ -52,6 +52,7 @@ import {
import { getTimeSec } from '$utils/getTimeSec';
import { Toast } from '$store';
import { config } from '$config';
+import { NetworkOverloadedError } from '@tonkeeper/shared/utils/blockchain';
const tokensWithAllowedEncryption = [TokenType.TON, TokenType.Jetton];
@@ -259,18 +260,20 @@ export const Send: FC = ({ route }) => {
setPreparing(false);
}
}, [
- amount,
- comment,
- currency,
- decimals,
+ recipient,
dispatch,
- isCommentEncrypted,
+ currencyAdditionalParams,
+ currency,
+ parsedAmount,
+ amount.all,
+ amount.value,
tokenType,
jettonWalletAddress,
- parsedAmount,
- recipient,
- trcPayload,
+ decimals,
+ comment,
+ isCommentEncrypted,
trcToken,
+ trcPayload,
]);
const unlock = useUnlockVault();
@@ -323,9 +326,13 @@ export const Send: FC = ({ route }) => {
setSending(false);
onDone();
},
- onFail: () => {
+ onFail: (error) => {
setSending(false);
- onFail(new DismissedActionError());
+ onFail(
+ error instanceof NetworkOverloadedError
+ ? error
+ : new DismissedActionError(),
+ );
},
}),
);
diff --git a/packages/mobile/src/core/Send/steps/AddressStep/AddressStep.tsx b/packages/mobile/src/core/Send/steps/AddressStep/AddressStep.tsx
index 770caa4e4..cad9853d0 100644
--- a/packages/mobile/src/core/Send/steps/AddressStep/AddressStep.tsx
+++ b/packages/mobile/src/core/Send/steps/AddressStep/AddressStep.tsx
@@ -100,7 +100,7 @@ const AddressStepComponent: FC = (props) => {
return new TonWeb.Address(resolvedDomain.wallet.address).toString(
true,
true,
- true,
+ false,
) as string;
}
diff --git a/packages/mobile/src/core/Send/steps/ConfirmStep/ConfirmStep.style.ts b/packages/mobile/src/core/Send/steps/ConfirmStep/ConfirmStep.style.ts
index 6477a0a47..96de5f44f 100644
--- a/packages/mobile/src/core/Send/steps/ConfirmStep/ConfirmStep.style.ts
+++ b/packages/mobile/src/core/Send/steps/ConfirmStep/ConfirmStep.style.ts
@@ -104,3 +104,9 @@ export const WarningRow = styled.View`
export const WarningIcon = styled.View`
margin-top: ${ns(2)}px;
`;
+
+export const WalletNameRow = styled.View`
+ flex-direction: row;
+ align-items: center;
+ justify-content: flex-end;
+`;
diff --git a/packages/mobile/src/core/Send/steps/ConfirmStep/ConfirmStep.tsx b/packages/mobile/src/core/Send/steps/ConfirmStep/ConfirmStep.tsx
index c9478a2ae..0c3d9b829 100644
--- a/packages/mobile/src/core/Send/steps/ConfirmStep/ConfirmStep.tsx
+++ b/packages/mobile/src/core/Send/steps/ConfirmStep/ConfirmStep.tsx
@@ -25,6 +25,7 @@ import { BatteryState } from '@tonkeeper/shared/utils/battery';
import { TokenType } from '$core/Send/Send.interface';
import { useBalancesState, useWallet } from '@tonkeeper/shared/hooks';
import { tk } from '$wallet';
+import { Steezy, WalletIcon, isAndroid } from '@tonkeeper/uikit';
const ConfirmStepComponent: FC = (props) => {
const {
@@ -226,9 +227,15 @@ const ConfirmStepComponent: FC = (props) => {
{t('send_screen_steps.comfirm.wallet')}
-
- {tk.wallet.config.emoji} {tk.wallet.config.name}
-
+
+
+
+ {tk.wallet.config.name}
+
@@ -370,3 +377,10 @@ const ConfirmStepComponent: FC = (props) => {
};
export const ConfirmStep = memo(ConfirmStepComponent);
+
+const styles = Steezy.create({
+ emoji: {
+ fontSize: isAndroid ? 17 : 20,
+ marginTop: isAndroid ? -1 : 1,
+ },
+});
diff --git a/packages/mobile/src/core/Settings/Settings.tsx b/packages/mobile/src/core/Settings/Settings.tsx
index da00ea3d4..ba607996e 100644
--- a/packages/mobile/src/core/Settings/Settings.tsx
+++ b/packages/mobile/src/core/Settings/Settings.tsx
@@ -3,13 +3,11 @@ import { useDispatch } from 'react-redux';
import Rate, { AndroidMarket } from 'react-native-rate';
import { Alert, Linking, Platform, View } from 'react-native';
import DeviceInfo from 'react-native-device-info';
-import { useBottomTabBarHeight } from '@react-navigation/bottom-tabs';
-import Animated from 'react-native-reanimated';
import { TapGestureHandler } from 'react-native-gesture-handler';
import * as S from './Settings.style';
-import { Icon, PopupSelect, ScrollHandler, Spacer, Text } from '$uikit';
-import { Icon as NewIcon } from '@tonkeeper/uikit';
+import { Icon, PopupSelect, Spacer, Text } from '$uikit';
+import { Icon as NewIcon, Screen } from '@tonkeeper/uikit';
import { useShouldShowTokensButton } from '$hooks/useShouldShowTokensButton';
import { useNavigation } from '@tonkeeper/router';
import { List } from '@tonkeeper/uikit';
@@ -17,7 +15,6 @@ import {
AppStackRouteNames,
MainStackRouteNames,
SettingsStackRouteNames,
- openDeleteAccountDone,
openDevMenu,
openLegalDocuments,
openManageTokens,
@@ -42,7 +39,6 @@ import { SearchEngine, useBrowserStore } from '$store';
import AnimatedLottieView from 'lottie-react-native';
import { Steezy } from '$styles';
import { i18n, t } from '@tonkeeper/shared/i18n';
-import { trackEvent } from '$utils/stats';
import { openAppearance } from '$core/ModalContainer/AppearanceModal';
import { config } from '$config';
import {
@@ -56,10 +52,12 @@ import { mapNewNftToOldNftData } from '$utils/mapNewNftToOldNftData';
import { WalletListItem } from '@tonkeeper/shared/components';
import { useSubscriptions } from '@tonkeeper/shared/hooks/useSubscriptions';
import { nativeLocaleNames } from '@tonkeeper/shared/i18n/translations';
+import { useSafeAreaInsets } from 'react-native-safe-area-context';
export const Settings: FC = () => {
const animationRef = useRef(null);
const devMenuHandlerRef = useRef(null);
+ const { bottom: paddingBottom } = useSafeAreaInsets();
const flags = useFlags([
'disable_apperance',
@@ -70,7 +68,6 @@ export const Settings: FC = () => {
]);
const nav = useNavigation();
- const tabBarHeight = useBottomTabBarHeight();
const fiatCurrency = useWalletCurrency();
const dispatch = useDispatch();
@@ -126,20 +123,8 @@ export const Settings: FC = () => {
}, []);
const handleResetWallet = useCallback(() => {
- Alert.alert(t('settings_reset_alert_title'), t('settings_reset_alert_caption'), [
- {
- text: t('cancel'),
- style: 'cancel',
- },
- {
- text: t('settings_reset_alert_button'),
- style: 'destructive',
- onPress: () => {
- dispatch(walletActions.cleanWallet());
- },
- },
- ]);
- }, [dispatch]);
+ nav.navigate('/logout-warning');
+ }, [nav]);
const handleStopWatchWallet = useCallback(() => {
Alert.alert(t('settings_delete_watch_account'), undefined, [
@@ -211,25 +196,8 @@ export const Settings: FC = () => {
}, []);
const handleDeleteAccount = useCallback(() => {
- Alert.alert(
- t('settings_delete_alert_title', { space: Platform.OS === 'ios' ? '\n' : ' ' }),
- t('settings_delete_alert_caption'),
- [
- {
- text: t('cancel'),
- style: 'cancel',
- },
- {
- text: t('settings_delete_alert_button'),
- style: 'destructive',
- onPress: () => {
- trackEvent('delete_wallet');
- openDeleteAccountDone();
- },
- },
- ],
- );
- }, []);
+ nav.openModal('/logout-warning', { isDelete: true });
+ }, [nav]);
const handleCustomizePress = useCallback(
() => nav.navigate(AppStackRouteNames.CustomizeWallet),
@@ -251,7 +219,7 @@ export const Settings: FC = () => {
const accountNfts = useNftsState((s) => s.accountNfts);
const hasDiamods = useMemo(() => {
- if (!wallet || wallet.isWatchOnly) {
+ if (!wallet || wallet?.isWatchOnly) {
return false;
}
@@ -266,13 +234,12 @@ export const Settings: FC = () => {
return (
-
-
+
+
@@ -323,7 +290,7 @@ export const Settings: FC = () => {
onPress={handleManageTokens}
/>
)}
- {hasSubscriptions && (
+ {!!wallet && !wallet.isWatchOnly && hasSubscriptions && (
{
-
-
-
+
+
);
};
diff --git a/packages/mobile/src/core/StakingPoolDetails/StakingPoolDetails.style.ts b/packages/mobile/src/core/StakingPoolDetails/StakingPoolDetails.style.ts
index ce064bf96..9271de075 100644
--- a/packages/mobile/src/core/StakingPoolDetails/StakingPoolDetails.style.ts
+++ b/packages/mobile/src/core/StakingPoolDetails/StakingPoolDetails.style.ts
@@ -90,10 +90,10 @@ export const DetailsButtonContainer = styled.View`
export const HeaderWrap = styled.View`
align-items: center;
- padding-horizontal: ${ns(16)}px;
`;
export const FlexRow = styled.View`
+ padding-horizontal: ${ns(12)}px;
flex-direction: row;
justify-content: space-between;
margin-top: ${ns(16)}px;
diff --git a/packages/mobile/src/core/StakingPoolDetails/StakingPoolDetails.tsx b/packages/mobile/src/core/StakingPoolDetails/StakingPoolDetails.tsx
index e2717c095..c6db0f3d4 100644
--- a/packages/mobile/src/core/StakingPoolDetails/StakingPoolDetails.tsx
+++ b/packages/mobile/src/core/StakingPoolDetails/StakingPoolDetails.tsx
@@ -9,7 +9,6 @@ import {
import {
Button,
Highlight,
- IconButton,
ScrollHandler,
Spacer,
StakedTonIcon,
@@ -27,12 +26,11 @@ import { t } from '@tonkeeper/shared/i18n';
import { useFlag } from '$utils/flags';
import { formatter } from '@tonkeeper/shared/formatter';
import { IStakingLink, StakingLinkType } from './types';
-import { Icon, List, Steezy } from '@tonkeeper/uikit';
+import { ActionButtons, Icon, List, Steezy } from '@tonkeeper/uikit';
import { getLinkIcon, getLinkTitle, getSocialLinkType } from './utils';
import { SafeAreaView } from 'react-native-safe-area-context';
import { Linking } from 'react-native';
import { PoolImplementationType } from '@tonkeeper/core/src/TonAPI';
-import BigNumber from 'bignumber.js';
import { ListItemRate } from '../../tabs/Wallet/components/ListItemRate';
import { useStakingState, useWallet, useWalletCurrency } from '@tonkeeper/shared/hooks';
import { StakingManager } from '$wallet/managers/StakingManager';
@@ -154,19 +152,6 @@ export const StakingPoolDetails: FC = (props) => {
const isLiquidTF = pool.implementation === PoolImplementationType.LiquidTF;
- const nextReward = useMemo(() => {
- if (!stakingJetton || !pool.cycle_length) {
- return;
- }
-
- return formatter.format(
- new BigNumber(balance.totalTon)
- .multipliedBy(pool.apy / 100)
- .dividedBy(31536000)
- .multipliedBy(pool.cycle_length),
- );
- }, [balance.totalTon, pool.apy, pool.cycle_length, stakingJetton]);
-
const stakingJettonView = useMemo(
() =>
stakingJettonMetadata ? (
@@ -249,27 +234,24 @@ export const StakingPoolDetails: FC = (props) => {
-
- {!isWatchOnly ? (
- <>
-
-
-
-
-
-
- >
- ) : null}
+
{hasPendingDeposit ? (
<>
@@ -336,23 +318,11 @@ export const StakingPoolDetails: FC = (props) => {
>
) : null}
- {/* {hasAnyBalance && stakingJetton && isLiquidTF ? (
- <>
-
-
-
-
- >
- ) : null} */}
-
- {t('staking.details.about_pool')}
-
{stakingJettonMetadata && hasAnyBalance ? (
<>
{stakingJettonView}
-
-
+
>
) : null}
diff --git a/packages/mobile/src/core/StakingSend/steps/ConfirmStep/ConfirmStep.style.ts b/packages/mobile/src/core/StakingSend/steps/ConfirmStep/ConfirmStep.style.ts
index 92e7d7acf..7afe38ee4 100644
--- a/packages/mobile/src/core/StakingSend/steps/ConfirmStep/ConfirmStep.style.ts
+++ b/packages/mobile/src/core/StakingSend/steps/ConfirmStep/ConfirmStep.style.ts
@@ -81,3 +81,9 @@ export const Icon = styled(FastImage).attrs({
export const ItemSkeleton = styled.View`
align-self: flex-end;
`;
+
+export const WalletNameRow = styled.View`
+ flex-direction: row;
+ align-items: center;
+ justify-content: flex-end;
+`;
diff --git a/packages/mobile/src/core/StakingSend/steps/ConfirmStep/ConfirmStep.tsx b/packages/mobile/src/core/StakingSend/steps/ConfirmStep/ConfirmStep.tsx
index 8e6c4684a..d9da8fa0b 100644
--- a/packages/mobile/src/core/StakingSend/steps/ConfirmStep/ConfirmStep.tsx
+++ b/packages/mobile/src/core/StakingSend/steps/ConfirmStep/ConfirmStep.tsx
@@ -21,6 +21,7 @@ import { t } from '@tonkeeper/shared/i18n';
import { PoolInfo } from '@tonkeeper/core/src/TonAPI';
import { SkeletonLine } from '$uikit/Skeleton/SkeletonLine';
import { tk } from '$wallet';
+import { Steezy, WalletIcon, isAndroid } from '@tonkeeper/uikit';
interface Props extends StepComponentProps {
transactionType: StakingTransactionType;
@@ -119,9 +120,15 @@ const ConfirmStepComponent: FC = (props) => {
{t('send_screen_steps.comfirm.wallet')}
-
- {tk.wallet.config.emoji} {tk.wallet.config.name}
-
+
+
+
+ {tk.wallet.config.name}
+
@@ -212,3 +219,10 @@ const ConfirmStepComponent: FC = (props) => {
};
export const ConfirmStep = memo(ConfirmStepComponent);
+
+const styles = Steezy.create({
+ emoji: {
+ fontSize: isAndroid ? 17 : 20,
+ marginTop: isAndroid ? -1 : 1,
+ },
+});
diff --git a/packages/mobile/src/core/Wallet/ToncoinScreen.tsx b/packages/mobile/src/core/Wallet/ToncoinScreen.tsx
index 1f7aec007..b52a3b131 100644
--- a/packages/mobile/src/core/Wallet/ToncoinScreen.tsx
+++ b/packages/mobile/src/core/Wallet/ToncoinScreen.tsx
@@ -6,17 +6,17 @@ import { Button, PopupMenu, PopupMenuItem } from '$uikit';
import { MainStackRouteNames, openDAppBrowser, openSend } from '$navigation';
import { openRequireWalletModal } from '$core/ModalContainer/RequireWallet/RequireWallet';
import { walletActions } from '$store/wallet';
-import { Linking, View } from 'react-native';
+import { View } from 'react-native';
import { delay, ns } from '$utils';
import { CryptoCurrencies, CryptoCurrency, Decimals } from '$shared/constants';
-import { i18n, t } from '@tonkeeper/shared/i18n';
+import { t } from '@tonkeeper/shared/i18n';
import { useNavigation } from '@tonkeeper/router';
import { Chart } from '$shared/components/Chart/new/Chart';
import { formatter } from '$utils/formatter';
import { Toast } from '$store';
import { useFlags } from '$utils/flags';
import { HideableAmount } from '$core/HideableAmount/HideableAmount';
-import { Icon, Screen, TonIcon, IconButton, IconButtonList } from '@tonkeeper/uikit';
+import { Icon, Screen, TonIcon, ActionButtons, Spacer } from '@tonkeeper/uikit';
import { ActivityList } from '@tonkeeper/shared/components';
import { useTonActivityList } from '@tonkeeper/shared/query/hooks/useTonActivityList';
@@ -114,22 +114,6 @@ const HeaderList = memo(() => {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
- const handleOpenAction = useCallback(async (action: any) => {
- try {
- let shouldOpenInBrowser = action.openInBrowser;
- if (action.scheme) {
- shouldOpenInBrowser = await Linking.canOpenURL(action.scheme);
- }
- if (shouldOpenInBrowser) {
- return Linking.openURL(action.url);
- }
- openDAppBrowser(action.url);
- } catch (e) {
- console.log(e);
- openDAppBrowser(action.url);
- }
- }, []);
-
const { amount, tokenPrice } = useWalletInfo();
const handleReceive = useCallback(() => {
@@ -147,13 +131,6 @@ const HeaderList = memo(() => {
openSend({ currency: 'ton' });
}, [wallet]);
- const handleOpenExchange = useCallback(() => {
- if (!wallet) {
- return openRequireWalletModal();
- }
- nav.openModal('Exchange');
- }, [nav, wallet]);
-
const handlePressSwap = useCallback(() => {
if (wallet) {
nav.openModal('Swap');
@@ -196,39 +173,36 @@ const HeaderList = memo(() => {
-
-
-
- {!isWatchOnly ? (
-
- ) : null}
-
- {!isWatchOnly ? (
-
- ) : null}
- {!flags.disable_swap && !isWatchOnly && (
-
- )}
-
-
-
+
+
+
+
+
{shouldShowChart && (
<>
diff --git a/packages/mobile/src/core/Wallet/Wallet.style.ts b/packages/mobile/src/core/Wallet/Wallet.style.ts
index 3a7d33303..f7de96af4 100644
--- a/packages/mobile/src/core/Wallet/Wallet.style.ts
+++ b/packages/mobile/src/core/Wallet/Wallet.style.ts
@@ -11,6 +11,10 @@ export const Header = styled.View`
margin-horizontal: ${ns(-16)}px;
`;
+export const ActionsWrap = styled.View`
+ padding-horizontal: ${ns(16)}px;
+`;
+
export const TokenInfoWrap = styled.View`
align-items: center;
padding-horizontal: ${ns(28)}px;
@@ -24,7 +28,6 @@ export const FlexRow = styled.View`
flex-direction: row;
justify-content: space-between;
margin-top: ${ns(16)}px;
- margin-bottom: ${ns(28)}px;
`;
export const ExploreButtons = styled.View`
diff --git a/packages/mobile/src/hooks/useHaveNfts.ts b/packages/mobile/src/hooks/useHaveNfts.ts
new file mode 100644
index 000000000..375cd6cce
--- /dev/null
+++ b/packages/mobile/src/hooks/useHaveNfts.ts
@@ -0,0 +1,6 @@
+import { useApprovedNfts } from '$hooks/useApprovedNfts';
+
+export function useHaveNfts(): boolean {
+ const nfts = useApprovedNfts();
+ return nfts.enabled.length > 0;
+}
diff --git a/packages/mobile/src/modals/ExchangeModal.tsx b/packages/mobile/src/modals/ExchangeModal.tsx
index 711c1c9fb..7f1653d21 100644
--- a/packages/mobile/src/modals/ExchangeModal.tsx
+++ b/packages/mobile/src/modals/ExchangeModal.tsx
@@ -13,6 +13,7 @@ import { openChooseCountry } from '$navigation';
import { useSelectedCountry } from '$store/zustand/methodsToBuy/useSelectedCountry';
import { CountryButton } from '@tonkeeper/shared/components';
import { config } from '$config';
+import { useWallet } from '@tonkeeper/shared/hooks';
export const ExchangeModal = () => {
const [showAll, setShowAll] = React.useState(false);
@@ -65,6 +66,9 @@ export const ExchangeModal = () => {
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
}, [showAll]);
+ const wallet = useWallet();
+ const watchOnly = wallet && wallet.isWatchOnly;
+
const [segmentIndex, setSegmentIndex] = useState(0);
const isLoading = buy.length === 0 && sell.length === 0;
@@ -79,11 +83,15 @@ export const ExchangeModal = () => {
}
title={
- setSegmentIndex(segment)}
- index={segmentIndex}
- items={[t('exchange_modal.buy'), t('exchange_modal.sell')]}
- />
+ watchOnly ? (
+ categories && categories[0] && categories[0].title
+ ) : (
+ setSegmentIndex(segment)}
+ index={segmentIndex}
+ items={[t('exchange_modal.buy'), t('exchange_modal.sell')]}
+ />
+ )
}
/>
@@ -97,9 +105,11 @@ export const ExchangeModal = () => {
{categories.map((category, cIndex) => (
{cIndex > 0 ? : null}
-
- {category.title}
-
+ {!(watchOnly && cIndex === 0) ? (
+
+ {category.title}
+
+ ) : null}
{category.items.map((item, idx, arr) => (
= memo((props) => {
+ const { isDelete } = props;
+
+ const nav = useNavigation();
+ const dispatch = useDispatch();
+
+ const [checked, setChecked] = useState(false);
+
+ const handleContinue = useCallback(() => {
+ nav.closeModal?.();
+
+ if (isDelete) {
+ trackEvent('delete_wallet');
+ InteractionManager.runAfterInteractions(() => {
+ openDeleteAccountDone();
+ });
+ } else {
+ InteractionManager.runAfterInteractions(() => {
+ dispatch(walletActions.cleanWallet());
+ });
+ }
+ }, [dispatch, isDelete, nav]);
+
+ const handleBackup = useCallback(() => {
+ nav.replaceModal('/backup-warning');
+ }, [nav]);
+
+ return (
+
+
+
+
+
+ {isDelete ? t('logout_modal.delete_title') : t('logout_modal.title')}
+
+
+
+ {isDelete ? t('logout_modal.delete_caption') : t('logout_modal.caption')}
+
+
+ setChecked((s) => !s)} />
+
+
+ setChecked((s) => !s)}>
+ {t('logout_modal.agreement')}
+
+
+
+
+ {t('logout_modal.backup_button')}
+
+
+
+
+
+
+
+
+
+ );
+});
+
+const styles = Steezy.create(({ colors }) => ({
+ container: {
+ marginHorizontal: 16,
+ marginTop: 48,
+ },
+ content: {
+ marginTop: 32,
+ marginVertical: 32,
+ backgroundColor: colors.backgroundContent,
+ borderRadius: 16,
+ padding: 16,
+ flexDirection: 'row',
+ alignItems: 'flex-start',
+ },
+ agreementContainer: {
+ flex: 1,
+ alignItems: 'flex-start',
+ },
+ desk: {
+ paddingHorizontal: 16,
+ },
+ dot: {
+ backgroundColor: colors.textPrimary,
+ width: 2.8,
+ height: 2.8,
+ borderRadius: 2.8 / 2,
+ marginTop: 9.8,
+ marginRight: 9.5,
+ },
+}));
diff --git a/packages/mobile/src/modals/index.ts b/packages/mobile/src/modals/index.ts
index f0bf42e4a..aa5ba75ed 100644
--- a/packages/mobile/src/modals/index.ts
+++ b/packages/mobile/src/modals/index.ts
@@ -1,2 +1,3 @@
export * from './ExchangeModal';
export * from './BackupWarningModal';
+export * from './LogoutWarningModal';
diff --git a/packages/mobile/src/navigation/MainStack/MainStack.interface.ts b/packages/mobile/src/navigation/MainStack/MainStack.interface.ts
index ce8af9cc4..a57116be6 100644
--- a/packages/mobile/src/navigation/MainStack/MainStack.interface.ts
+++ b/packages/mobile/src/navigation/MainStack/MainStack.interface.ts
@@ -38,4 +38,5 @@ export type MainStackParamList = {
[MainStackRouteNames.Backup]: {};
[MainStackRouteNames.BackupPhrase]: {};
[MainStackRouteNames.BackupCheckPhrase]: {};
+ [MainStackRouteNames.Settings]: {};
};
diff --git a/packages/mobile/src/navigation/MainStack/MainStack.tsx b/packages/mobile/src/navigation/MainStack/MainStack.tsx
index c2a9f5106..4260e3b72 100644
--- a/packages/mobile/src/navigation/MainStack/MainStack.tsx
+++ b/packages/mobile/src/navigation/MainStack/MainStack.tsx
@@ -41,6 +41,7 @@ import { useExternalState } from '@tonkeeper/shared/hooks/useExternalState';
import { tk } from '$wallet';
import { MigrationStack } from '$navigation/MigrationStack';
import { useTonPriceUpdater } from '$hooks/useTonPriceUpdater';
+import { SettingsStack } from '$navigation/SettingsStack/SettingsStack';
const Stack = createNativeStackNavigator();
@@ -116,6 +117,7 @@ export const MainStack: FC = () => {
name={MainStackRouteNames.AddWatchOnlyStack}
component={AddWatchOnlyStack}
/>
+
@@ -157,6 +159,7 @@ export const MainStack: FC = () => {
{
);
diff --git a/packages/mobile/src/navigation/MainStack/TabStack/BackupIndicator.tsx b/packages/mobile/src/navigation/MainStack/TabStack/BackupIndicator.tsx
deleted file mode 100644
index f86d928fc..000000000
--- a/packages/mobile/src/navigation/MainStack/TabStack/BackupIndicator.tsx
+++ /dev/null
@@ -1,11 +0,0 @@
-import React from 'react';
-import { TabBarBadgeIndicator } from '$navigation/MainStack/TabStack/TabBarBadgeIndicator';
-import { useWalletSetup } from '@tonkeeper/shared/hooks';
-
-export const BackupIndicator: React.FC = () => {
- const { lastBackupAt } = useWalletSetup();
-
- const isVisible = lastBackupAt === null;
-
- return ;
-};
diff --git a/packages/mobile/src/navigation/MainStack/TabStack/TabStack.interface.ts b/packages/mobile/src/navigation/MainStack/TabStack/TabStack.interface.ts
index 0f5b3acee..fc3f178f4 100644
--- a/packages/mobile/src/navigation/MainStack/TabStack/TabStack.interface.ts
+++ b/packages/mobile/src/navigation/MainStack/TabStack/TabStack.interface.ts
@@ -3,7 +3,6 @@ import { TabsStackRouteNames } from '$navigation';
export type TabStackParamList = {
[TabsStackRouteNames.Balances]: {};
[TabsStackRouteNames.Activity]: {};
- [TabsStackRouteNames.NFT]: {};
[TabsStackRouteNames.BrowserStack]: {};
- [TabsStackRouteNames.SettingsStack]: {};
+ [TabsStackRouteNames.Collectibles]: {};
};
diff --git a/packages/mobile/src/navigation/MainStack/TabStack/TabStack.tsx b/packages/mobile/src/navigation/MainStack/TabStack/TabStack.tsx
index b7d40916d..812f77c1a 100644
--- a/packages/mobile/src/navigation/MainStack/TabStack/TabStack.tsx
+++ b/packages/mobile/src/navigation/MainStack/TabStack/TabStack.tsx
@@ -5,12 +5,11 @@ import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { StyleSheet } from 'react-native';
import { TabsStackRouteNames } from '$navigation';
import { TabStackParamList } from './TabStack.interface';
-import { Icon, ScrollPositionContext, View } from '$uikit';
+import { ScrollPositionContext, View } from '$uikit';
import { usePreloadChart } from '$hooks/usePreloadChart';
import { useTheme } from '$hooks/useTheme';
import { isAndroid, nfs, ns } from '$utils';
import { t } from '@tonkeeper/shared/i18n';
-import { SettingsStack } from '$navigation/SettingsStack/SettingsStack';
import { TabBarBadgeIndicator } from './TabBarBadgeIndicator';
import { WalletScreen } from '../../../tabs/Wallet/WalletScreen';
import Animated from 'react-native-reanimated';
@@ -18,13 +17,15 @@ import { FONT } from '$styled';
import { useCheckForUpdates } from '$hooks/useCheckForUpdates';
import { useLoadExpiringDomains } from '$store/zustand/domains/useExpiringDomains';
import { ActivityStack } from '$navigation/ActivityStack/ActivityStack';
-import { BackupIndicator } from '$navigation/MainStack/TabStack/BackupIndicator';
import { useFetchMethodsToBuy } from '$store/zustand/methodsToBuy/useMethodsToBuyStore';
import { trackEvent } from '$utils/stats';
import { useRemoteBridge } from '$tonconnect';
import { BrowserStack } from '$navigation/BrowserStack/BrowserStack';
import { useWallet } from '@tonkeeper/shared/hooks';
import { useDAppsNotifications } from '$store';
+import { Icon } from '@tonkeeper/uikit';
+import { Collectibles } from '$core/Colectibles/Collectibles';
+import { useHaveNfts } from '$hooks/useHaveNfts';
const Tab = createBottomTabNavigator();
@@ -33,6 +34,7 @@ export const TabStack: FC = () => {
const safeArea = useSafeAreaInsets();
const theme = useTheme();
const { shouldShowRedDot, removeRedDot } = useDAppsNotifications();
+ const haveNfts = useHaveNfts();
useRemoteBridge();
useLoadExpiringDomains();
@@ -40,10 +42,15 @@ export const TabStack: FC = () => {
usePreloadChart();
useCheckForUpdates();
- const tabBarStyle = { height: ns(64) + (safeArea.bottom > 0 ? ns(20) : 0) };
+ const tabBarStyle = useMemo(
+ () => ({
+ height: ns(64) + (safeArea.bottom > 0 ? ns(20) : 0),
+ }),
+ [safeArea.bottom],
+ );
const containerTabStyle = useMemo(
() => [tabBarStyle, styles.tabBarContainer, bottomSeparatorStyle],
- [safeArea.bottom, bottomSeparatorStyle, tabBarStyle],
+ [bottomSeparatorStyle, tabBarStyle],
);
const wallet = useWallet();
@@ -102,7 +109,7 @@ export const TabStack: FC = () => {
component={ActivityStack}
name={TabsStackRouteNames.Activity}
listeners={{
- tabPress: (e) => {
+ tabPress: () => {
removeRedDot();
},
}}
@@ -125,25 +132,22 @@ export const TabStack: FC = () => {
tabBarIcon: ({ color }) => ,
}}
listeners={{
- tabPress: (e) => {
+ tabPress: () => {
trackEvent('browser_open');
},
}}
/>
) : null}
- (
-
-
- {!isWatchOnly ? : null}
-
- ),
- }}
- />
+ {haveNfts ? (
+ ,
+ }}
+ />
+ ) : null}
);
};
diff --git a/packages/mobile/src/navigation/ModalStack.tsx b/packages/mobile/src/navigation/ModalStack.tsx
index 18e5db475..25f0917f3 100644
--- a/packages/mobile/src/navigation/ModalStack.tsx
+++ b/packages/mobile/src/navigation/ModalStack.tsx
@@ -32,7 +32,7 @@ import { NFTSend } from '$core/NFTSend/NFTSend';
import { ReceiveInscriptionModal } from '@tonkeeper/shared/modals/ReceiveInscriptionModal';
import { CustomizeWallet } from '$core/CustomizeWallet/CustomizeWallet';
import { TokenDetails } from '../components/TokenDetails/TokenDetails';
-import { BackupWarningModal, ExchangeModal } from '$modals';
+import { BackupWarningModal, ExchangeModal, LogoutWarningModal } from '$modals';
const Stack = createModalStackNavigator(ProvidersWithNavigation);
@@ -50,6 +50,7 @@ export const ModalStack = React.memo(() => (
+
diff --git a/packages/mobile/src/navigation/hooks/useDeeplinkingResolvers.ts b/packages/mobile/src/navigation/hooks/useDeeplinkingResolvers.ts
index fa75b385b..2c04baa8b 100644
--- a/packages/mobile/src/navigation/hooks/useDeeplinkingResolvers.ts
+++ b/packages/mobile/src/navigation/hooks/useDeeplinkingResolvers.ts
@@ -471,7 +471,7 @@ export function useDeeplinkingResolvers() {
const excessesAccount =
!config.get('disable_battery_send') &&
tk.wallet.battery.state.data.balance !== '0'
- ? await tk.wallet.battery.getExcessesAccount()
+ ? tk.wallet.battery.excessesAccount
: null;
await openSignRawModal(
diff --git a/packages/mobile/src/navigation/navigationNames.ts b/packages/mobile/src/navigation/navigationNames.ts
index b4858e154..1029c89bc 100644
--- a/packages/mobile/src/navigation/navigationNames.ts
+++ b/packages/mobile/src/navigation/navigationNames.ts
@@ -55,13 +55,13 @@ export enum MainStackRouteNames {
Backup = 'Backup',
BackupPhrase = 'BackupPhrase',
BackupCheckPhrase = 'BackupCheckPhrase',
+ Settings = 'SettingsStack',
}
export enum TabsStackRouteNames {
Balances = 'Balances',
- NFT = 'TabNFT',
BrowserStack = 'BrowserStack',
- SettingsStack = 'SettingsStack',
+ Collectibles = 'Collectibles',
Activity = 'Activity',
}
diff --git a/packages/mobile/src/screens/ChangePinBiometry/ChangePinBiometry.tsx b/packages/mobile/src/screens/ChangePinBiometry/ChangePinBiometry.tsx
index a611c8416..7c836ca9b 100644
--- a/packages/mobile/src/screens/ChangePinBiometry/ChangePinBiometry.tsx
+++ b/packages/mobile/src/screens/ChangePinBiometry/ChangePinBiometry.tsx
@@ -61,6 +61,7 @@ export const ChangePinBiometry: FC = () => {
{t('later')}
}
+ hideBackButton
/>
diff --git a/packages/mobile/src/screens/ChooseWallets/ChooseWallets.tsx b/packages/mobile/src/screens/ChooseWallets/ChooseWallets.tsx
index 59f73b1c1..71f0242b8 100644
--- a/packages/mobile/src/screens/ChooseWallets/ChooseWallets.tsx
+++ b/packages/mobile/src/screens/ChooseWallets/ChooseWallets.tsx
@@ -11,6 +11,7 @@ import { RouteProp } from '@react-navigation/native';
import { Address } from '@tonkeeper/shared/Address';
import { formatter } from '@tonkeeper/shared/formatter';
import { useImportWallet } from '$hooks/useImportWallet';
+import { DEFAULT_WALLET_VERSION } from '$wallet/constants';
export const ChooseWallets: FC<{
route: RouteProp;
@@ -22,7 +23,10 @@ export const ChooseWallets: FC<{
const [selectedVersions, setSelectedVersions] = useState(
walletsInfo
- .filter((item) => item.balance > 0 || item.tokens)
+ .filter(
+ (item) =>
+ item.balance > 0 || item.tokens || item.version === DEFAULT_WALLET_VERSION,
+ )
.map((item) => item.version),
);
const [loading, setLoading] = useState(false);
diff --git a/packages/mobile/src/screens/StartScreen/StartScreen.tsx b/packages/mobile/src/screens/StartScreen/StartScreen.tsx
index 6431b3ca8..58cc6eecb 100644
--- a/packages/mobile/src/screens/StartScreen/StartScreen.tsx
+++ b/packages/mobile/src/screens/StartScreen/StartScreen.tsx
@@ -16,6 +16,9 @@ import { MainStackRouteNames } from '$navigation';
import { useDispatch } from 'react-redux';
import { walletActions } from '$store/wallet';
import { useNavigation } from '@tonkeeper/router';
+import { network } from '@tonkeeper/core';
+import { config } from '$config';
+import DeviceInfo from 'react-native-device-info';
const HEIGHT_RATIO = deviceHeight / 844;
@@ -31,10 +34,30 @@ export const StartScreen = memo(() => {
const logoShapesPosX = origShapesWidth / 2 - dimensions.width / 2;
const logoShapesPosY = origShapesHeight / 2 - (origShapesHeight * ratioHeight) / 2;
+ const unsubscribeNotifications = useCallback(async () => {
+ // unsubscribe from all notifications, if app was reinstalled
+ try {
+ const deviceId = DeviceInfo.getUniqueId();
+ const endpoint = `${config.get('tonapiIOEndpoint')}/unsubscribe`;
+
+ await network.post(endpoint, {
+ params: {
+ device: deviceId,
+ },
+ });
+ } catch {}
+ }, []);
+
const handleCreatePress = useCallback(() => {
dispatch(walletActions.generateVault());
+ unsubscribeNotifications();
nav.navigate(MainStackRouteNames.CreateWalletStack);
- }, [dispatch, nav]);
+ }, [dispatch, nav, unsubscribeNotifications]);
+
+ const handleImportPress = useCallback(() => {
+ unsubscribeNotifications();
+ nav.navigate(MainStackRouteNames.ImportWalletStack);
+ }, [nav, unsubscribeNotifications]);
return (
@@ -79,7 +102,7 @@ export const StartScreen = memo(() => {
diff --git a/packages/mobile/src/shared/components/ImportWalletForm/ImportWalletForm.style.ts b/packages/mobile/src/shared/components/ImportWalletForm/ImportWalletForm.style.ts
index 974a74a9b..f0f28371b 100644
--- a/packages/mobile/src/shared/components/ImportWalletForm/ImportWalletForm.style.ts
+++ b/packages/mobile/src/shared/components/ImportWalletForm/ImportWalletForm.style.ts
@@ -26,8 +26,8 @@ export const InputNumber = styled.TextInput.attrs({
top: 0;
padding-left: 0;
padding-right: 0;
- padding-top: ${ns(isAndroid ? 16.5 : 18.5)}px;
- padding-bottom: ${ns(isAndroid ? 14.5 : 17.5)}px;
+ padding-top: ${ns(isAndroid ? 17 : 18.5)}px;
+ padding-bottom: ${ns(isAndroid ? 15.5 : 17.5)}px;
${isAndroid ? 'text-align-vertical: top;' : ''}
z-index: 3;
position: absolute;
diff --git a/packages/mobile/src/shared/components/StakingListCell/StakingListCell.tsx b/packages/mobile/src/shared/components/StakingListCell/StakingListCell.tsx
index b09f39571..e9cb1dbcb 100644
--- a/packages/mobile/src/shared/components/StakingListCell/StakingListCell.tsx
+++ b/packages/mobile/src/shared/components/StakingListCell/StakingListCell.tsx
@@ -10,7 +10,7 @@ import * as S from './StakingListCell.style';
import { HideableAmount } from '$core/HideableAmount/HideableAmount';
import { JettonBalanceModel } from '$store/models';
import { t } from '@tonkeeper/shared/i18n';
-import { Icon, ListSeparator, Pressable, isAndroid, useTheme } from '@tonkeeper/uikit';
+import { Icon, Pressable, isAndroid, useTheme } from '@tonkeeper/uikit';
import { useBackgroundHighlighted } from '@tonkeeper/shared/hooks/useBackgroundHighlighted';
import Animated from 'react-native-reanimated';
@@ -22,7 +22,6 @@ interface Props {
stakingJetton?: JettonBalanceModel;
icon?: ReactNode;
iconSource?: Source | ImageRequireSource | null;
- separator?: boolean;
isWidget?: boolean;
isWidgetAccent?: boolean;
isBuyTon?: boolean;
@@ -42,7 +41,6 @@ const StakingListCellComponent: FC = (props) => {
stakingJetton,
icon,
iconSource,
- separator,
id,
isWidget,
isWidgetAccent,
@@ -151,7 +149,6 @@ const StakingListCellComponent: FC = (props) => {
) : null}
- {separator ? : null}
>
);
};
diff --git a/packages/mobile/src/store/wallet/interface.ts b/packages/mobile/src/store/wallet/interface.ts
index 065a41af9..b74d08a6a 100644
--- a/packages/mobile/src/store/wallet/interface.ts
+++ b/packages/mobile/src/store/wallet/interface.ts
@@ -49,7 +49,7 @@ export type SendCoinsAction = PayloadAction<{
isSendAll?: boolean;
decimals?: number;
onDone: () => void;
- onFail: () => void;
+ onFail: (error?: Error) => void;
sendWithBattery?: boolean;
currencyAdditionalParams?: CurrencyAdditionalParams;
}>;
diff --git a/packages/mobile/src/store/wallet/sagas.ts b/packages/mobile/src/store/wallet/sagas.ts
index 0d7c2548b..e91f47ddb 100644
--- a/packages/mobile/src/store/wallet/sagas.ts
+++ b/packages/mobile/src/store/wallet/sagas.ts
@@ -38,6 +38,7 @@ import { InscriptionAdditionalParams, TokenType } from '$core/Send/Send.interfac
import { WalletConfig, WalletContractVersion, WalletNetwork } from '$wallet/WalletTypes';
import { v4 as uuidv4 } from 'uuid';
import { vault as multiWalletVault } from '$wallet';
+import RNRestart from 'react-native-restart';
function* generateVaultWorker() {
try {
@@ -345,7 +346,7 @@ function* sendCoinsWorker(action: SendCoinsAction) {
onDone();
} catch (e) {
- action.payload.onFail();
+ action.payload.onFail(e);
console.error(e);
e && debugLog(e.message);
@@ -377,6 +378,7 @@ function* cleanWalletWorker(action: CleanWalletAction) {
});
yield call([tk, 'removeAllWallets']);
+ RNRestart.restart();
} else {
yield call(
useConnectedAppsStore.getState().actions.unsubscribeFromAllNotifications,
@@ -389,12 +391,14 @@ function* cleanWalletWorker(action: CleanWalletAction) {
yield call([tk, 'removeWallet'], tk.wallet.identifier);
+ yield call(trackEvent, 'reset_wallet');
+
if (tk.wallets.size > 0) {
navigate(TabsStackRouteNames.Balances);
+ } else {
+ RNRestart.restart();
}
}
-
- yield call(trackEvent, 'reset_wallet');
} catch (e) {
e && debugLog(e.message);
yield put(Toast.fail, e.message);
diff --git a/packages/mobile/src/tabs/Activity/ActivityScreen.tsx b/packages/mobile/src/tabs/Activity/ActivityScreen.tsx
index bbdf97dcb..4acd7c2fe 100644
--- a/packages/mobile/src/tabs/Activity/ActivityScreen.tsx
+++ b/packages/mobile/src/tabs/Activity/ActivityScreen.tsx
@@ -111,33 +111,37 @@ export const ActivityScreen = memo(() => {
const renderNotificationsHeader = notifications.length ? (
- {notifications.slice(0, Math.min(newNotificationsCount, 2)).map((notification) => (
-
- ))}
-
-
-
-
- }
- rightContent={
- newNotificationsCount - 2 > 0 ? (
-
- {newNotificationsCount - 2}
+
+ {notifications
+ .slice(0, Math.min(newNotificationsCount, 2))
+ .map((notification) => (
+
+ ))}
+
+
+
- ) : null
- }
- onPress={handleOpenNotificationsScreen}
- title={t('notifications.notifications')}
- subtitle={t('notifications.from_connected')}
- chevron
- />
-
+ }
+ rightContent={
+ newNotificationsCount - 2 > 0 ? (
+
+ {newNotificationsCount - 2}
+
+ ) : null
+ }
+ onPress={handleOpenNotificationsScreen}
+ title={t('notifications.notifications')}
+ subtitle={t('notifications.from_connected')}
+ chevron
+ />
+
+
) : undefined;
@@ -196,4 +200,7 @@ const styles = Steezy.create(({ colors }) => ({
listStyle: {
marginBottom: 8,
},
+ gap8: {
+ gap: 8,
+ },
}));
diff --git a/packages/mobile/src/tabs/Wallet/WalletScreen.tsx b/packages/mobile/src/tabs/Wallet/WalletScreen.tsx
index 5b95de5c7..8a589ccbc 100644
--- a/packages/mobile/src/tabs/Wallet/WalletScreen.tsx
+++ b/packages/mobile/src/tabs/Wallet/WalletScreen.tsx
@@ -1,80 +1,47 @@
import { memo, useCallback, useEffect, useMemo } from 'react';
-import { i18n, t } from '@tonkeeper/shared/i18n';
-import {
- Button,
- IconButton,
- IconButtonList,
- Screen,
- Text,
- List,
- View,
- PagerView,
- Spacer,
- copyText,
- Haptics,
-} from '@tonkeeper/uikit';
+import { t } from '@tonkeeper/shared/i18n';
+import { Screen, Text, View, copyText, Haptics, Icon } from '@tonkeeper/uikit';
import { InternalNotification, Tag } from '$uikit';
import { useNavigation } from '@tonkeeper/router';
-import { ScanQRButton } from '../../components/ScanQRButton';
-import { RefreshControl, useWindowDimensions } from 'react-native';
-import { NFTCardItem } from './NFTCardItem';
import { useDispatch } from 'react-redux';
-import { ns } from '$utils';
import { useIsFocused } from '@react-navigation/native';
import { useBalance } from './hooks/useBalance';
-import { ListItemRate } from './components/ListItemRate';
-import { TonIcon } from '@tonkeeper/uikit';
-import { CryptoCurrencies, TabletMaxWidth } from '$shared/constants';
-import { useBottomTabBarHeight } from '$hooks/useBottomTabBarHeight';
+import { TabletMaxWidth } from '$shared/constants';
import { useInternalNotifications } from './hooks/useInternalNotifications';
import { mainActions } from '$store/main';
-import { useTonkens } from './hooks/useTokens';
-import { useApprovedNfts } from '$hooks/useApprovedNfts';
-import { useTheme } from '$hooks/useTheme';
-import { useTokenPrice } from '$hooks/useTokenPrice';
import { Steezy } from '$styles';
-import { WalletContentList } from './components/WalletContentList';
-import { useFlags } from '$utils/flags';
import { useUpdatesStore } from '$store/zustand/updates/useUpdatesStore';
import { UpdatesCell } from '$core/ApprovalCell/Updates/UpdatesCell';
import { UpdateState } from '$store/zustand/updates/types';
import { ShowBalance } from '$core/HideableAmount/ShowBalance';
-import { Events, SendAnalyticsFrom } from '$store/models';
-import { openRequireWalletModal } from '$core/ModalContainer/RequireWallet/RequireWallet';
-import { openWallet } from '$core/Wallet/ToncoinScreen';
-import { trackEvent } from '$utils/stats';
import { ExpiringDomainCell } from './components/ExpiringDomainCell';
import { BatteryIcon } from '@tonkeeper/shared/components/BatteryIcon/BatteryIcon';
import { useNetInfo } from '@react-native-community/netinfo';
import { format } from 'date-fns';
import { getLocale } from '$utils/date';
import { TouchableOpacity } from 'react-native-gesture-handler';
-import { useWallet, useWalletCurrency, useWalletStatus } from '@tonkeeper/shared/hooks';
+import { useWallet, useWalletStatus } from '@tonkeeper/shared/hooks';
import { WalletSelector } from './components/WalletSelector';
-import { useInscriptionBalances } from '$hooks/useInscriptionBalances';
+import { MainStackRouteNames } from '$navigation';
+import { WalletActionButtons } from './components/WalletActionButtons/WalletActionButtons';
+import { WalletContentList } from './components/WalletContentList';
+import { usePreparedWalletContent } from './content-providers/utils/usePreparedWalletContent';
+import { FinishSetupList } from './components/FinishSetupList';
+import { BackupIndicator } from './components/Tabs/BackupIndicator';
export const WalletScreen = memo(({ navigation }) => {
- const flags = useFlags(['disable_swap']);
- const tabBarHeight = useBottomTabBarHeight();
const dispatch = useDispatch();
- const theme = useTheme();
const nav = useNavigation();
- const tokens = useTonkens();
- const { enabled: inscriptions } = useInscriptionBalances();
- const { enabled: nfts } = useApprovedNfts();
const wallet = useWallet();
const shouldUpdate =
useUpdatesStore((state) => state.update.state) !== UpdateState.NOT_STARTED;
- const balance = useBalance(tokens.total.fiat);
- const tonPrice = useTokenPrice(CryptoCurrencies.Ton);
- const currency = useWalletCurrency();
+
+ const preparedContent = usePreparedWalletContent();
+ const balance = useBalance(preparedContent);
const { isReloading: isRefreshing, updatedAt: walletUpdatedAt } = useWalletStatus();
const isFocused = useIsFocused();
-
- const tronBalances = undefined;
-
const notifications = useInternalNotifications();
const { isConnected } = useNetInfo();
@@ -87,40 +54,7 @@ export const WalletScreen = memo(({ navigation }) => {
return () => clearTimeout(timer);
}, [dispatch]);
- const handlePressSwap = useCallback(() => {
- if (wallet) {
- nav.openModal('Swap');
- } else {
- openRequireWalletModal();
- }
- }, [nav, wallet]);
-
- const handlePressBuy = useCallback(() => {
- if (wallet) {
- nav.openModal('Exchange');
- } else {
- openRequireWalletModal();
- }
- }, [nav, wallet]);
-
- const handlePressSend = useCallback(() => {
- if (wallet) {
- trackEvent(Events.SendOpen, { from: SendAnalyticsFrom.WalletScreen });
- nav.go('Send', { from: SendAnalyticsFrom.WalletScreen });
- } else {
- openRequireWalletModal();
- }
- }, [nav, wallet]);
-
- const handlePressRecevie = useCallback(() => {
- if (wallet) {
- nav.go('ReceiveModal');
- } else {
- openRequireWalletModal();
- }
- }, [nav, wallet]);
-
- const handleCreateWallet = () => nav.navigate('/add-wallet');
+ const handleNavigateToSettingsStack = () => nav.navigate(MainStackRouteNames.Settings);
const handleRefresh = useCallback(() => {
if (!wallet) {
@@ -143,7 +77,7 @@ export const WalletScreen = memo(({ navigation }) => {
const ListHeader = useMemo(
() => (
-
+
{notifications.map((notification, i) => (
{
{shouldUpdate && }
-
-
-
+
+ {!isWatchOnly && }
{wallet && isConnected !== false ? (
@@ -186,7 +119,6 @@ export const WalletScreen = memo(({ navigation }) => {
) : null}
-
{wallet && wallet.isTestnet ? (
<>
Testnet
@@ -199,51 +131,17 @@ export const WalletScreen = memo(({ navigation }) => {
) : null}
-
- {!isWatchOnly ? (
-
- ) : null}
-
- {!isWatchOnly ? (
-
- ) : null}
- {!flags.disable_swap && !isWatchOnly && (
-
- )}
-
+
{wallet && !wallet.isWatchOnly && (
<>
+
>
)}
),
[
- balance.total.fiat,
- flags.disable_swap,
- handlePressBuy,
- handlePressRecevie,
- handlePressSend,
- handlePressSwap,
+ balance,
isConnected,
isWatchOnly,
notifications,
@@ -253,134 +151,33 @@ export const WalletScreen = memo(({ navigation }) => {
],
);
- // TODO: rewrite
- const dimensions = useWindowDimensions();
- const mockupCardSize = {
- width: ns(114),
- height: ns(166),
- };
-
- const numColumn = 3;
- const indent = ns(8);
- const heightRatio = mockupCardSize.height / mockupCardSize.width;
-
- const nftCardSize = useMemo(() => {
- const width = dimensions.width / numColumn - indent;
- const height = width * heightRatio;
-
- return { width, height };
- }, [dimensions.width]);
-
- const isPagerView =
- nfts.length &&
- tokens.list.length + inscriptions.length >= 2 &&
- inscriptions.length + tokens.list.length + nfts.length + 1 > 10;
-
if (!wallet) {
- return (
-
- }
- hideBackButton
- />
-
- {ListHeader}
-
- openWallet(CryptoCurrencies.Ton)}
- leftContent={}
- chevron
- subtitle={
-
- }
- />
-
-
- {!wallet && (
-
-
-
-
-
- )}
-
- );
+ return null;
}
return (
}
- rightContent={!isWatchOnly ? : null}
+ rightContent={
+
+ {!isWatchOnly ? : null}
+
+
+ }
hideBackButton
/>
- {isPagerView ? (
-
-
- {ListHeader}
-
-
-
-
-
-
-
-
-
-
- (
-
-
-
- )}
- refreshControl={
-
- }
- />
-
-
-
- ) : (
-
- )}
+
);
});
@@ -424,7 +221,15 @@ const styles = Steezy.create(({ isTablet }) => ({
alignItems: 'center',
},
addressContainer: {
+ marginBottom: 8,
+ marginTop: 4,
flexDirection: 'row',
alignItems: 'center',
},
+ gearContainer: {
+ width: 48,
+ height: 48,
+ justifyContent: 'center',
+ alignItems: 'center',
+ },
}));
diff --git a/packages/mobile/src/tabs/Wallet/components/FinishSetupList.tsx b/packages/mobile/src/tabs/Wallet/components/FinishSetupList.tsx
index 9e0db12c4..7163a3fef 100644
--- a/packages/mobile/src/tabs/Wallet/components/FinishSetupList.tsx
+++ b/packages/mobile/src/tabs/Wallet/components/FinishSetupList.tsx
@@ -4,6 +4,7 @@ import {
Icon,
IconNames,
List,
+ Spacer,
Steezy,
Switch,
View,
@@ -149,11 +150,11 @@ export const FinishSetupList = memo(() => {
-
+
{items.map((item) => (
{
/>
))}
+
>
);
});
diff --git a/packages/mobile/src/tabs/Wallet/components/NFTsList.tsx b/packages/mobile/src/tabs/Wallet/components/NFTsList.tsx
deleted file mode 100644
index d7cf4105c..000000000
--- a/packages/mobile/src/tabs/Wallet/components/NFTsList.tsx
+++ /dev/null
@@ -1,46 +0,0 @@
-import React, { memo, useMemo } from 'react';
-import { View } from "$uikit";
-import { NFTCardItem } from "../NFTCardItem";
-import { Steezy } from '$styles';
-import { useWindowDimensions } from 'react-native';
-
-interface NFTsListProps {
- nfts: any; // TODO: add types
-}
-
-const mockupCardSize = {
- width: 114,
- height: 166
-};
-
-const numColumn = 3;
-const indent = 8;
-const heightRatio = mockupCardSize.height / mockupCardSize.width;
-
-export const NFTsList = memo(({ nfts }) => {
- const dimensions = useWindowDimensions();
-
- const size = useMemo(() => {
- const width = (dimensions.width / numColumn) - indent;
- const height = width * heightRatio;
-
- return { width, height };
- }, [dimensions.width]);
-
- return (
-
- {nfts.map((item, key) => (
-
-
-
- ))}
-
- );
-});
-
-const styles = Steezy.create({
- nftElements: {
- flexDirection: 'row',
- flexWrap: 'wrap',
- }
-});
diff --git a/packages/mobile/src/tabs/Wallet/components/StakingWidget.tsx b/packages/mobile/src/tabs/Wallet/components/StakingWidget.tsx
deleted file mode 100644
index 08a9bc17f..000000000
--- a/packages/mobile/src/tabs/Wallet/components/StakingWidget.tsx
+++ /dev/null
@@ -1,95 +0,0 @@
-import { useStakingStatuses } from '$hooks/useStakingStatuses';
-import { MainStackRouteNames } from '$navigation';
-import { StakingListCell } from '$shared/components';
-import { View } from '$uikit';
-import { List } from '$uikit/List/old/List';
-import React, { FC, memo, useCallback } from 'react';
-import { useNavigation } from '@tonkeeper/router';
-import { Steezy } from '$styles';
-import { FlashCountKeys, useFlashCount } from '$store';
-import { StakingWidgetStatus } from './StakingWidgetStatus';
-import { logEvent } from '@amplitude/analytics-browser';
-import { t } from '@tonkeeper/shared/i18n';
-import { Flash } from '@tonkeeper/uikit';
-import { useStakingState } from '@tonkeeper/shared/hooks';
-
-interface Props {
- isWatchOnly: boolean;
- showBuyButton: boolean;
-}
-
-const StakingWidgetComponent: FC = (props) => {
- const { isWatchOnly, showBuyButton } = props;
-
- const nav = useNavigation();
-
- const highestApyPool = useStakingState((s) => s.highestApyPool);
- const [flashShownCount] = useFlashCount(FlashCountKeys.StakingWidget);
-
- const stakingInfo = useStakingStatuses();
-
- const handleStakingPress = useCallback(() => {
- logEvent('staking_open');
- nav.push(MainStackRouteNames.Staking);
- }, [nav]);
-
- const handleBuyPress = useCallback(() => {
- nav.openModal('Exchange');
- }, [nav]);
-
- const staked = stakingInfo.length > 0;
-
- const apyDescription = highestApyPool
- ? t('staking.widget_desc', {
- apy: highestApyPool.apy.toFixed(2),
- })
- : '';
-
- const shouldShowBuyButton = showBuyButton && !isWatchOnly && !staked;
-
- return (
-
-
- {stakingInfo.map((item) => (
-
- ))}
- {!isWatchOnly && (
- = 2}>
-
-
- )}
- {shouldShowBuyButton ? (
-
- ) : null}
-
-
- );
-};
-
-export const StakingWidget = memo(StakingWidgetComponent);
-
-const styles = Steezy.create({
- container: {
- paddingHorizontal: 16,
- // paddingTop: 32,
- },
-});
diff --git a/packages/mobile/src/tabs/Wallet/components/Tabs/BackupIndicator.tsx b/packages/mobile/src/tabs/Wallet/components/Tabs/BackupIndicator.tsx
new file mode 100644
index 000000000..48d503ed6
--- /dev/null
+++ b/packages/mobile/src/tabs/Wallet/components/Tabs/BackupIndicator.tsx
@@ -0,0 +1,27 @@
+import React from 'react';
+import { useWalletSetup } from '@tonkeeper/shared/hooks';
+import { Steezy, View } from '@tonkeeper/uikit';
+
+export const BackupIndicator: React.FC = () => {
+ const { lastBackupAt } = useWalletSetup();
+
+ const isVisible = lastBackupAt === null;
+
+ if (!isVisible) {
+ return null;
+ }
+
+ return ;
+};
+
+const styles = Steezy.create(({ colors }) => ({
+ indicator: {
+ position: 'absolute',
+ top: 10,
+ right: 4,
+ height: 6,
+ width: 6,
+ borderRadius: 3,
+ backgroundColor: colors.accentRed,
+ },
+}));
diff --git a/packages/mobile/src/tabs/Wallet/components/TokenList.tsx b/packages/mobile/src/tabs/Wallet/components/TokenList.tsx
deleted file mode 100644
index 94ff48fb3..000000000
--- a/packages/mobile/src/tabs/Wallet/components/TokenList.tsx
+++ /dev/null
@@ -1,67 +0,0 @@
-import React from 'react';
-import { openJetton } from '$navigation';
-import { CryptoCurrencies, LockupNames } from '$shared/constants';
-import { View } from '$uikit';
-import { List } from '$uikit';
-import { TonIcon } from '@tonkeeper/uikit';
-import { memo } from 'react';
-import { ListItemRate } from './ListItemRate';
-import { openWallet } from '$core/Wallet';
-
-interface TokenListProps {
- tokens: any; // TODO: add types
- balance: any; // TODO: add types
- rates: any; // TODO: add types
-}
-
-export const TokenList = memo(({ tokens, balance, rates }) => {
- return (
-
-
- openWallet(CryptoCurrencies.Ton)}
- value={balance.amount.formatted}
- subvalue={balance.amount.fiat}
- leftContent={}
- subtitle={
-
- }
- />
- {balance.lockup.map((item, key) => (
- }
- subtitle={rates.price}
- />
- ))}
- {tokens.list.map((item) => (
- openJetton(item.address.rawAddress)}
- picture={item.iconUrl}
- title={item.name}
- value={item.quantity.formatted}
- label={item.symbol}
- // TODO:
- // subvalue={item.rate?.fiatValue}
- // subtitle={item.rate && (
- //
- // )}
- />
- ))}
-
-
- );
-});
diff --git a/packages/mobile/src/tabs/Wallet/components/WalletActionButtons/WalletActionButtons.tsx b/packages/mobile/src/tabs/Wallet/components/WalletActionButtons/WalletActionButtons.tsx
new file mode 100644
index 000000000..ae59412e6
--- /dev/null
+++ b/packages/mobile/src/tabs/Wallet/components/WalletActionButtons/WalletActionButtons.tsx
@@ -0,0 +1,139 @@
+import React, { memo, useCallback } from 'react';
+import { ActionButtons } from '@tonkeeper/uikit';
+import { openRequireWalletModal } from '$core/ModalContainer/RequireWallet/RequireWallet';
+import { trackEvent } from '$utils/stats';
+import { Events, SendAnalyticsFrom } from '$store/models';
+import { useWallet } from '@tonkeeper/shared/hooks';
+import { useNavigation } from '@tonkeeper/router';
+import { store } from '$store';
+import { MainStackRouteNames, openScanQR, openSend } from '$navigation';
+import { Address } from '@tonkeeper/core';
+import { CryptoCurrencies } from '$shared/constants';
+import { DeeplinkOrigin, useDeeplinking } from '$libs/deeplinking';
+import { useFlags } from '$utils/flags';
+import { t } from '@tonkeeper/shared/i18n';
+
+export const WalletActionButtons = memo(() => {
+ const wallet = useWallet();
+ const nav = useNavigation();
+ const deeplinking = useDeeplinking();
+ const flags = useFlags(['disable_swap']);
+
+ const isWatchOnly = wallet.isWatchOnly;
+
+ const handlePressSwap = useCallback(() => {
+ if (wallet) {
+ nav.openModal('Swap');
+ } else {
+ openRequireWalletModal();
+ }
+ }, [nav, wallet]);
+
+ const handlePressBuy = useCallback(() => {
+ if (wallet) {
+ nav.openModal('Exchange');
+ } else {
+ openRequireWalletModal();
+ }
+ }, [nav, wallet]);
+
+ const handlePressSend = useCallback(() => {
+ if (wallet) {
+ trackEvent(Events.SendOpen, { from: SendAnalyticsFrom.WalletScreen });
+ nav.go('Send', { from: SendAnalyticsFrom.WalletScreen });
+ } else {
+ openRequireWalletModal();
+ }
+ }, [nav, wallet]);
+
+ const handlePressReceive = useCallback(() => {
+ if (wallet) {
+ nav.go('ReceiveModal');
+ } else {
+ openRequireWalletModal();
+ }
+ }, [nav, wallet]);
+
+ const handlePressStaking = useCallback(() => {
+ trackEvent('staking_open');
+ nav.go(MainStackRouteNames.Staking);
+ }, [nav]);
+
+ const handlePressScanQR = React.useCallback(() => {
+ if (store.getState().wallet.wallet) {
+ openScanQR((address) => {
+ if (Address.isValid(address)) {
+ setTimeout(() => {
+ openSend({ currency: CryptoCurrencies.Ton, address });
+ }, 200);
+
+ return true;
+ }
+
+ const resolver = deeplinking.getResolver(address, {
+ delay: 200,
+ origin: DeeplinkOrigin.QR_CODE,
+ });
+
+ if (resolver) {
+ resolver();
+ return true;
+ }
+
+ return false;
+ });
+ } else {
+ openRequireWalletModal();
+ }
+ }, [deeplinking]);
+
+ return (
+
+ );
+});
diff --git a/packages/mobile/src/tabs/Wallet/components/WalletContentList.tsx b/packages/mobile/src/tabs/Wallet/components/WalletContentList.tsx
index a969cabfb..70862a1b8 100644
--- a/packages/mobile/src/tabs/Wallet/components/WalletContentList.tsx
+++ b/packages/mobile/src/tabs/Wallet/components/WalletContentList.tsx
@@ -1,434 +1,135 @@
-import React, { memo, ReactNode, useMemo } from 'react';
-import { t } from '@tonkeeper/shared/i18n';
-import {
- Screen,
- Spacer as SpacerView,
- SpacerSizes,
- View,
- List,
- PagerView,
- DEFAULT_TOKEN_LOGO,
-} from '@tonkeeper/uikit';
+import React, { memo } from 'react';
+import { Screen, View, List, ListSeparator } from '@tonkeeper/uikit';
import { Steezy } from '$styles';
import { RefreshControl } from 'react-native';
-import { openJetton, openTonInscription } from '$navigation';
-import { Rate } from '../hooks/useBalance';
import { ListItemRate } from './ListItemRate';
-import { TonIcon, TonIconProps } from '@tonkeeper/uikit';
-import { CryptoCurrencies, LockupNames } from '$shared/constants';
-import { NFTsList } from './NFTsList';
-import { TokenPrice } from '$hooks/useTokenPrice';
+import { TonIcon } from '@tonkeeper/uikit';
import { useTheme } from '$hooks/useTheme';
-import { ListSeparator } from '$uikit/List/ListSeparator';
-import { StakingWidget } from './StakingWidget';
import { HideableAmount } from '$core/HideableAmount/HideableAmount';
-import { openWallet } from '$core/Wallet/ToncoinScreen';
-import { TronBalance } from '@tonkeeper/core/src/TronAPI/TronAPIGenerated';
-import { WalletCurrency } from '@tonkeeper/core';
-import { formatter } from '@tonkeeper/shared/formatter';
import { Text } from '@tonkeeper/uikit';
-import { JettonVerification } from '$store/models';
-import { config } from '$config';
-import { useWallet, useWalletCurrency } from '@tonkeeper/shared/hooks';
-import { CardsWidget } from '$components';
-import { InscriptionBalance } from '@tonkeeper/core/src/TonAPI';
-import { ListItemProps } from '@tonkeeper/uikit/src/components/List/ListItem';
-import { FinishSetupList } from './FinishSetupList';
-import BigNumber from 'bignumber.js';
-
-enum ContentType {
- Token,
- Collectibles,
- Spacer,
- NFTCardsRow,
- Staking,
- Cards,
- Setup,
-}
-
-type TokenItem = {
- type: ContentType.Token;
- key: string;
- isFirst?: boolean;
- isLast?: boolean;
- subtitleStyle?: ListItemProps['subtitleStyle'];
- onPress?: () => void;
- title: string;
- subtitle?: string;
- value?: string | ReactNode;
- subvalue?: string;
- rate?: Rate;
- picture?: string;
- tonIcon?: boolean | TonIconProps;
- tag?: string;
-};
-
-type SpacerItem = {
- key: string;
- type: ContentType.Spacer;
- bottom: SpacerSizes;
-};
-
-type NFTCardsRowItem = {
- key: string;
- type: ContentType.NFTCardsRow;
- items: any; // TODO:
-};
-
-type StakingItem = {
- key: string;
- type: ContentType.Staking;
- isWatchOnly: boolean;
- showBuyButton: boolean;
-};
-
-type CardsItem = {
- key: string;
- type: ContentType.Cards;
-};
-
-type SetupItem = {
- key: string;
- type: ContentType.Setup;
-};
-
-type Content =
- | TokenItem
- | SpacerItem
- | NFTCardsRowItem
- | StakingItem
- | CardsItem
- | SetupItem;
-
-const RenderItem = ({ item }: { item: Content }) => {
- switch (item.type) {
- case ContentType.Token:
- const renderLeftContent = () => {
- if (typeof item.tonIcon === 'object') {
- return ;
- } else if (typeof item.tonIcon === 'boolean') {
- return ;
- }
- };
-
- const containerStyle = [
- item.isFirst && styles.firstListItem,
- item.isLast && styles.lastListItem,
- styles.containerListItem,
- ];
-
- return (
-
-
-
- {item.title}
-
- {!!item.tag && (
-
-
- {item.tag.toUpperCase()}
-
-
- )}
-
- }
- picture={item.picture}
- value={
- typeof item.value === 'string' ? (
- {` ${item.value}`}
- ) : (
- item.value
- )
- }
- subvalue={
- item.subvalue && (
-
- {item.subvalue}
-
- )
- }
- subtitle={
- item.subtitle ||
- (item.rate && (
-
- ))
- }
- subtitleStyle={item.subtitleStyle}
- />
- {!item.isLast && }
-
- );
- case ContentType.Spacer:
- return ;
- case ContentType.NFTCardsRow:
- return ;
- case ContentType.Staking:
- return (
-
- );
- case ContentType.Cards:
- return ;
- case ContentType.Setup:
- return ;
+import { CellItemToRender } from '../content-providers/utils/types';
+
+const RenderItem = ({ item }: { item: CellItemToRender }) => {
+ const renderLeftContent = () => {
+ if (typeof item.tonIcon === 'object') {
+ return ;
+ } else if (typeof item.tonIcon === 'boolean') {
+ return ;
+ }
+ };
+
+ const containerStyle = [
+ item.isFirst && styles.firstListItem,
+ item.isLast && styles.lastListItem,
+ styles.containerListItem,
+ ];
+
+ const RenderComponent = item.RenderComponent;
+
+ if (RenderComponent) {
+ return (
+
+
+
+ );
}
-};
-
-interface BalancesListProps {
- currency: WalletCurrency;
- tokens: any; // TODO:
- balance: any; // TODO:
- tonPrice: TokenPrice;
- nfts?: any; // TODO:
- inscriptions: InscriptionBalance[];
- tronBalances?: TronBalance[];
- handleRefresh: () => void;
- isRefreshing: boolean;
- isFocused: boolean;
- ListHeaderComponent?: React.ReactElement;
-}
-
-export const WalletContentList = memo(
- ({
- currency,
- tokens,
- balance,
- tonPrice,
- nfts,
- handleRefresh,
- isRefreshing,
- inscriptions,
- isFocused,
- ListHeaderComponent,
- }) => {
- const theme = useTheme();
-
- const fiatCurrency = useWalletCurrency();
- const shouldShowTonDiff = fiatCurrency !== WalletCurrency.TON;
-
- const wallet = useWallet();
- const isWatchOnly = wallet && wallet.isWatchOnly;
- const isLockup = wallet && wallet.isLockup;
- const identifier = wallet.identifier;
- const showStaking = isWatchOnly ? balance.staking.amount.nano !== '0' : true;
- const showBuyButton =
- !isLockup && new BigNumber(balance.ton.amount.nano).isLessThan(50);
-
- const data = useMemo(() => {
- const content: Content[] = [];
-
- // Tokens
- content.push({
- type: ContentType.Token,
- key: 'ton',
- title: 'Toncoin',
- onPress: () => openWallet(CryptoCurrencies.Ton),
- value: balance.ton.amount.formatted,
- subvalue: balance.ton.amount.fiat,
- tonIcon: true,
- rate: {
- percent: shouldShowTonDiff ? tonPrice.fiatDiff.percent : '',
- price: tonPrice.formatted.fiat ?? '-',
- trend: tonPrice.fiatDiff.trend,
- },
- isLast: !showStaking,
- });
-
- if (balance.lockup.length > 0) {
- content.push(
- ...balance.lockup.map((item) => ({
- key: item.type,
- type: ContentType.Token,
- tonIcon: { locked: true },
- title: LockupNames[item.type],
- value: item.amount.formatted,
- subvalue: item.amount.fiat,
- subtitle: tonPrice.formatted.fiat ?? '-',
- })),
- );
- }
-
- if (showStaking) {
- content.push({
- key: 'staking',
- type: ContentType.Staking,
- isWatchOnly,
- showBuyButton,
- });
- }
- if (!isWatchOnly) {
- content.push({
- key: `setup_${identifier}`,
- type: ContentType.Setup,
- });
- }
-
- content.push({
- key: 'ton_section_spacer',
- type: ContentType.Spacer,
- bottom: 32,
- });
-
- if (!config.get('disable_holders_cards') && !isWatchOnly) {
- content.push({
- key: 'cards',
- type: ContentType.Cards,
- });
- }
-
- content.push(
- ...tokens.list.map((item, index) => ({
- key: 'token_' + item.address.rawAddress,
- isFirst: index === 0,
- type: ContentType.Token,
- onPress: () => openJetton(item.address.rawAddress),
- picture: item.iconUrl,
- title: item.symbol,
- value: item.lock ? (
+ return (
+
+
+
+ {item.title}
+
+ {!!item.tag && (
+
+
+ {item.tag.toUpperCase()}
+
+
+ )}
+
+ }
+ picture={item.picture}
+ value={
+ typeof item.value === 'string' ? (
{` ${item.value}`}
+ ) : (
+ item.value
+ )
+ }
+ subvalue={
+ item.fiatRate && (
+
- {item.quantity.formatted}
-
- {' '}
- ·{' '}
-
-
- {item.lock.formatted}
-
+ {item.fiatRate.total.formatted}
- ) : (
- item.quantity.formatted
- ),
- subvalue: item.rate.total,
- rate: item.rate.price
- ? {
- price: item.rate.price,
- percent: item.price.fiatDiff.percent,
- trend: item.price.fiatDiff.trend,
- }
- : undefined,
- subtitleStyle:
- !config.get('disable_show_unverified_token') &&
- item.verification === JettonVerification.NONE &&
- styles.unverifiedSubtitleStyle,
- subtitle:
- !config.get('disable_show_unverified_token') &&
- item.verification === JettonVerification.NONE
- ? t('approval.unverified_token')
- : undefined,
- })),
- );
-
- if (inscriptions?.length > 0) {
- content.push(
- ...inscriptions.map((item) => ({
- key: 'inscriptions' + item.ticker,
- onPress: () => openTonInscription({ ticker: item.ticker, type: item.type }),
- type: ContentType.Token,
- tag: item.type,
- picture: DEFAULT_TOKEN_LOGO,
- title: item.ticker,
- value: formatter.formatNano(item.balance, { decimals: item.decimals }),
- subvalue: formatter.format('0', { currency, currencySeparator: 'wide' }),
- rate: {
- price: formatter.format('0', { currency, currencySeparator: 'wide' }),
- },
- })),
- );
- }
-
- const firstTonkenElement = content[0] as TokenItem;
- const lastTokenElement = content[content.length - 1] as TokenItem;
-
- if (tokens.list.length > 0) {
- content.push({
- key: 'spacer_nft',
- type: ContentType.Spacer,
- bottom: 32,
- });
- }
-
- // Make list; set corners
- firstTonkenElement.isFirst = true;
- lastTokenElement.isLast = true;
-
- if (nfts) {
- const numColumns = 3;
- for (let i = 0; i < Math.ceil(nfts.length / numColumns); i++) {
- content.push({
- key: 'nft_' + i,
- type: ContentType.NFTCardsRow,
- items: nfts.slice(i * numColumns, i * numColumns + numColumns),
- });
+ )
}
- }
-
- content.push({
- key: 'spacer_bottom',
- type: ContentType.Spacer,
- bottom: 12,
- });
+ subtitle={
+ item.subtitle ||
+ (item.fiatRate && (
+
+ ))
+ }
+ subtitleStyle={item.subtitleStyle}
+ />
+
+ );
+};
- return content;
- }, [
- balance,
- shouldShowTonDiff,
- tonPrice,
- showStaking,
- isWatchOnly,
- tokens.list,
- inscriptions,
- nfts,
- showBuyButton,
- identifier,
- currency,
- ]);
+interface WalletContentListProps {
+ walletContent: CellItemToRender[];
+ handleRefresh: () => void;
+ isRefreshing: boolean;
+ isFocused: boolean;
+ ListHeaderComponent?: React.ReactElement;
+ ListFooterComponent?: React.ReactElement | null;
+}
- const ListComponent = nfts ? Screen.FlashList : PagerView.FlatList;
+function ItemSeparatorComponent() {
+ return (
+
+
+
+ );
+}
- return (
-
- }
- />
- );
- },
-);
+export const WalletContentList = memo((props) => {
+ const theme = useTheme();
+
+ return (
+
+ }
+ />
+ );
+});
const styles = Steezy.create(({ colors, corners }) => ({
unverifiedSubtitleStyle: {
@@ -452,6 +153,9 @@ const styles = Steezy.create(({ colors, corners }) => ({
backgroundColor: colors.backgroundContent,
marginHorizontal: 16,
},
+ separatorContainer: {
+ paddingHorizontal: 16,
+ },
valueText: {
textAlign: 'right',
flexShrink: 1,
diff --git a/packages/mobile/src/tabs/Wallet/components/WalletSelector.tsx b/packages/mobile/src/tabs/Wallet/components/WalletSelector.tsx
index 6a4f6329a..fad3394fd 100644
--- a/packages/mobile/src/tabs/Wallet/components/WalletSelector.tsx
+++ b/packages/mobile/src/tabs/Wallet/components/WalletSelector.tsx
@@ -8,12 +8,12 @@ import {
Text,
TouchableOpacity,
View,
+ WalletIcon,
deviceWidth,
getWalletColorHex,
isAndroid,
} from '@tonkeeper/uikit';
import React, { FC, memo, useCallback } from 'react';
-import { Text as RNText } from 'react-native';
import { useNavigation } from '@tonkeeper/router';
import { FlashCountKeys, useFlashCount } from '$store';
import { tk } from '$wallet';
@@ -39,7 +39,11 @@ const WalletSelectorComponent: FC = () => {
]}
disabled={!tk.migrationData || flashShownCount >= 3}
>
- {wallet.config.emoji}
+
diff --git a/packages/mobile/src/tabs/Wallet/content-providers/dependencies/inscriptions.ts b/packages/mobile/src/tabs/Wallet/content-providers/dependencies/inscriptions.ts
new file mode 100644
index 000000000..a537a0a00
--- /dev/null
+++ b/packages/mobile/src/tabs/Wallet/content-providers/dependencies/inscriptions.ts
@@ -0,0 +1,18 @@
+import { DependencyPrototype } from './utils/prototype';
+import { tk } from '$wallet';
+
+import { TonInscriptionsState } from '$wallet/managers/TonInscriptions';
+
+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);
+ }
+}
diff --git a/packages/mobile/src/tabs/Wallet/content-providers/dependencies/jettons.ts b/packages/mobile/src/tabs/Wallet/content-providers/dependencies/jettons.ts
new file mode 100644
index 000000000..07177ddbb
--- /dev/null
+++ b/packages/mobile/src/tabs/Wallet/content-providers/dependencies/jettons.ts
@@ -0,0 +1,56 @@
+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';
+
+export class JettonBalancesDependency extends DependencyPrototype<
+ JettonsState,
+ Pick
+> {
+ constructor() {
+ super(tk.wallet.jettons.state, (state) => ({
+ jettonBalances: state.jettonBalances,
+ jettonRates: state.jettonRates,
+ }));
+ }
+
+ public getJettonRate(
+ jettonAddress: string,
+ jettonBalance: string,
+ currency: string,
+ ): FiatRate | undefined {
+ const rate = this.state.jettonRates[Address.parse(jettonAddress).toRaw()];
+
+ if (!rate) {
+ return;
+ }
+
+ return {
+ percent: rate.ton ? rate.diff_24h : undefined,
+ price: {
+ raw: rate.fiat.toString(),
+ formatted: formatter.format(new BigNumber(rate.fiat), {
+ currency,
+ }),
+ },
+ trend:
+ rate.diff_24h.startsWith('+') || rate.diff_24h === '0' ? 'positive' : 'negative',
+ total: {
+ formatted: formatter.format(
+ new BigNumber(jettonBalance).multipliedBy(rate.fiat),
+ { currency },
+ ),
+ raw: new BigNumber(jettonBalance).multipliedBy(rate.fiat).toString(),
+ },
+ };
+ }
+
+ 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
new file mode 100644
index 000000000..1a89e3605
--- /dev/null
+++ b/packages/mobile/src/tabs/Wallet/content-providers/dependencies/staking.ts
@@ -0,0 +1,21 @@
+import { DependencyPrototype } from './utils/prototype';
+import { tk } from '$wallet';
+
+import { StakingState } from '$wallet/managers/StakingManager';
+import { AccountStakingInfo, PoolInfo } from '@tonkeeper/core/src/TonAPI';
+
+export class StakingDependency extends DependencyPrototype<
+ StakingState,
+ { info: AccountStakingInfo; pool: PoolInfo }[]
+> {
+ constructor() {
+ super(tk.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
new file mode 100644
index 000000000..66ada7c19
--- /dev/null
+++ b/packages/mobile/src/tabs/Wallet/content-providers/dependencies/stakingJettons.ts
@@ -0,0 +1,27 @@
+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';
+
+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);
+ }
+
+ get filterTokensBalancesFn(): (balance: JettonBalanceModel) => boolean {
+ return (balance: JettonBalanceModel) => {
+ const jettonAddress = Address.parse(balance.jettonAddress).toRaw();
+ return !this.state.stakingJettons[jettonAddress];
+ };
+ }
+}
diff --git a/packages/mobile/src/tabs/Wallet/content-providers/dependencies/tokenApproval.ts b/packages/mobile/src/tabs/Wallet/content-providers/dependencies/tokenApproval.ts
new file mode 100644
index 000000000..059c9d47a
--- /dev/null
+++ b/packages/mobile/src/tabs/Wallet/content-providers/dependencies/tokenApproval.ts
@@ -0,0 +1,50 @@
+import { DependencyPrototype } from './utils/prototype';
+import { tk } from '$wallet';
+
+import {
+ TokenApprovalState,
+ TokenApprovalStatus,
+} from '$wallet/managers/TokenApprovalManager';
+import { Address } from '@tonkeeper/shared/Address';
+import {
+ JettonBalanceModel,
+ JettonVerification,
+} from '$wallet/models/JettonBalanceModel';
+import { InscriptionBalance } from '@tonkeeper/core/src/TonAPI';
+
+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);
+ }
+
+ get filterInscriptionsFn(): (balance: InscriptionBalance) => boolean {
+ return (balance: InscriptionBalance) => {
+ const key = balance.ticker + '_' + balance.type;
+ const approvalStatus = this.state.tokens[key];
+
+ return !approvalStatus || approvalStatus.current !== TokenApprovalStatus.Declined;
+ };
+ }
+
+ get filterTokensBalancesFn(): (balance: JettonBalanceModel) => boolean {
+ return (balance: JettonBalanceModel) => {
+ const jettonAddress = Address.parse(balance.jettonAddress).toRaw();
+ const approvalStatus = this.state.tokens[jettonAddress];
+ const isBlacklisted = balance.verification === JettonVerification.BLACKLIST;
+
+ if (isBlacklisted) {
+ return approvalStatus?.current === TokenApprovalStatus.Approved;
+ }
+
+ return !approvalStatus || approvalStatus.current !== TokenApprovalStatus.Declined;
+ };
+ }
+}
diff --git a/packages/mobile/src/tabs/Wallet/content-providers/dependencies/tonBalances.ts b/packages/mobile/src/tabs/Wallet/content-providers/dependencies/tonBalances.ts
new file mode 100644
index 000000000..d78762f75
--- /dev/null
+++ b/packages/mobile/src/tabs/Wallet/content-providers/dependencies/tonBalances.ts
@@ -0,0 +1,50 @@
+import { DependencyPrototype } from './utils/prototype';
+import { tk } from '$wallet';
+import { BalancesState } from '$wallet/managers/BalancesManager';
+
+export enum TonBalanceType {
+ Liquid = 'Liquid',
+ Locked = 'Locked',
+ Restricted = 'Restricted',
+}
+
+export type TonBalance = {
+ type: TonBalanceType;
+ balance: string;
+};
+
+export class TonBalancesDependency extends DependencyPrototype<
+ BalancesState,
+ Pick
+> {
+ constructor() {
+ super(tk.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 },
+ ];
+
+ if (this.wallet.isLockup) {
+ balances.push(
+ { type: TonBalanceType.Locked, balance: this.state.tonLocked },
+ {
+ type: TonBalanceType.Restricted,
+ balance: this.state.tonRestricted,
+ },
+ );
+ }
+
+ return balances;
+ }
+}
diff --git a/packages/mobile/src/tabs/Wallet/content-providers/dependencies/tonPrice.ts b/packages/mobile/src/tabs/Wallet/content-providers/dependencies/tonPrice.ts
new file mode 100644
index 000000000..ecf6694d0
--- /dev/null
+++ b/packages/mobile/src/tabs/Wallet/content-providers/dependencies/tonPrice.ts
@@ -0,0 +1,55 @@
+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';
+
+export class TonPriceDependency extends DependencyPrototype<
+ PricesState,
+ Pick
+> {
+ constructor() {
+ super(tk.tonPrice.state, (state) => ({ ton: state.ton, currency: state.currency }));
+ }
+
+ protected shouldEmit(
+ prev: Pick,
+ cur: Pick,
+ ) {
+ 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();
+ }
+
+ public getFiatRate(balance: string): FiatRate | undefined {
+ const rate = this.state;
+
+ return {
+ percent: rate.ton ? rate.ton.diff_24h : undefined,
+ price: {
+ raw: rate.ton.fiat.toString(),
+ formatted: formatter.format(new BigNumber(rate.ton.fiat), {
+ currency: rate.currency,
+ }),
+ },
+ trend:
+ rate.ton.diff_24h.startsWith('+') || rate.ton.diff_24h === '0'
+ ? 'positive'
+ : 'negative',
+ total: {
+ formatted: formatter.format(new BigNumber(balance).multipliedBy(rate.ton.fiat), {
+ currency: rate.currency,
+ }),
+ raw: this.getRawTotal(balance),
+ },
+ };
+ }
+}
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
new file mode 100644
index 000000000..08b8e6061
--- /dev/null
+++ b/packages/mobile/src/tabs/Wallet/content-providers/dependencies/utils/prototype.ts
@@ -0,0 +1,78 @@
+import { Wallet } from '$wallet/Wallet';
+import { tk } from '$wallet';
+import { DefaultStateData, State } from '@tonkeeper/core';
+import { shallow } from 'zustand/shallow';
+
+type Subscriber = () => void;
+
+export type ExternalStateSelector = (
+ state: TStateData,
+) => TSelectedData;
+
+export class DependencyPrototype<
+ TStateData extends DefaultStateData,
+ TSelected = TStateData,
+> {
+ protected wallet: Wallet = tk.wallet;
+ public subscribers = new Set();
+
+ protected unsubscribe?: () => void;
+ protected latestSnapshot: TSelected;
+
+ protected shouldEmit(prev: TSelected, cur: TSelected): boolean {
+ return !shallow(cur, prev);
+ }
+
+ get state() {
+ return this.latestSnapshot;
+ }
+
+ constructor(
+ protected dataProvider: State,
+ protected selector: ExternalStateSelector,
+ ) {
+ const data = this.dataProvider?.getSnapshot();
+ this.latestSnapshot = this.selector(data);
+ this.subscribeToDataProvider();
+ }
+
+ protected subscribeToDataProvider() {
+ this.unsubscribe?.();
+ this.unsubscribe = this.dataProvider?.subscribe(() => {
+ this.onStateChanged();
+ });
+ }
+
+ private onStateChanged() {
+ const prevState = this.latestSnapshot;
+ const currentState = this.selector(this.dataProvider?.getSnapshot());
+ if (this.shouldEmit(prevState, currentState)) {
+ this.latestSnapshot = currentState;
+ this.emitSubscribers();
+ }
+ }
+
+ protected emitSubscribers() {
+ this.subscribers.forEach((subscriber) => {
+ try {
+ subscriber();
+ } catch (error) {
+ console.error('An error occurred when executing a subscriber: ', error);
+ }
+ });
+ }
+
+ public subscribe(subscriber: Subscriber) {
+ this.subscribers.add(subscriber);
+ return () => {
+ this.subscribers.delete(subscriber);
+ };
+ }
+
+ public setWallet(wallet: Wallet) {
+ 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
new file mode 100644
index 000000000..9f28412a9
--- /dev/null
+++ b/packages/mobile/src/tabs/Wallet/content-providers/inscriptions.ts
@@ -0,0 +1,67 @@
+import { ContentProviderPrototype } from './utils/prototype';
+import { CellItemToRender } from './utils/types';
+import { formatter } from '@tonkeeper/shared/formatter';
+import { Providers } from './providers';
+import { InscriptionBalance } from '@tonkeeper/core/src/TonAPI';
+import { InscriptionsDependency } from './dependencies/inscriptions';
+import { openTonInscription } from '$navigation';
+import { DEFAULT_TOKEN_LOGO } from '@tonkeeper/uikit';
+import { TonPriceDependency } from './dependencies/tonPrice';
+import { TokenApprovalDependency } from './dependencies/tokenApproval';
+
+export class InscriptionsContentProvider extends ContentProviderPrototype<{
+ inscriptions: InscriptionsDependency;
+ tonPrice: TonPriceDependency;
+ approval: TokenApprovalDependency;
+}> {
+ name = Providers.Inscriptions;
+ renderPriority = -2;
+
+ constructor(
+ tonPrice: TonPriceDependency,
+ inscriptions: InscriptionsDependency,
+ approval: TokenApprovalDependency,
+ ) {
+ super({
+ inscriptions,
+ tonPrice,
+ approval,
+ });
+ }
+
+ private filterByTokenApproval(inscriptions: InscriptionBalance[]) {
+ return inscriptions.filter(this.deps.approval.filterInscriptionsFn);
+ }
+
+ get itemsArray() {
+ return this.filterByTokenApproval(this.deps.inscriptions.state);
+ }
+
+ makeCellItemFromData(data: InscriptionBalance): CellItemToRender {
+ return {
+ key: data.ticker + '_' + data.type,
+ renderPriority: this.renderPriority,
+ onPress: () => openTonInscription({ ticker: data.ticker, type: data.type }),
+ title: data.ticker,
+ tag: data.type,
+ picture: DEFAULT_TOKEN_LOGO,
+ fiatRate: {
+ price: {
+ formatted: formatter.format(0, {
+ currency: this.deps.tonPrice.state.currency,
+ }),
+ raw: '0',
+ },
+ trend: 'negative',
+ total: {
+ formatted: formatter.format(0, {
+ currency: this.deps.tonPrice.state.currency,
+ }),
+ raw: '0',
+ },
+ percent: '',
+ },
+ value: formatter.formatNano(data.balance, { decimals: data.decimals }),
+ };
+ }
+}
diff --git a/packages/mobile/src/tabs/Wallet/content-providers/providers.ts b/packages/mobile/src/tabs/Wallet/content-providers/providers.ts
new file mode 100644
index 000000000..8b93afb2c
--- /dev/null
+++ b/packages/mobile/src/tabs/Wallet/content-providers/providers.ts
@@ -0,0 +1,6 @@
+export enum Providers {
+ TON = 'TON',
+ Tokens = 'Tokens',
+ Staking = 'Staking',
+ Inscriptions = 'Inscriptions',
+}
diff --git a/packages/mobile/src/tabs/Wallet/content-providers/staking.ts b/packages/mobile/src/tabs/Wallet/content-providers/staking.ts
new file mode 100644
index 000000000..837d07942
--- /dev/null
+++ b/packages/mobile/src/tabs/Wallet/content-providers/staking.ts
@@ -0,0 +1,126 @@
+import { ContentProviderPrototype } from './utils/prototype';
+import { CellItemToRender, FiatRate } from './utils/types';
+import { formatter } from '@tonkeeper/shared/formatter';
+import { Providers } from './providers';
+import { StakingWidgetStatus } from '../components/StakingWidgetStatus';
+import {
+ AccountStakingInfo,
+ PoolImplementationType,
+ PoolInfo,
+} from '@tonkeeper/core/src/TonAPI';
+import { TonPriceDependency } from './dependencies/tonPrice';
+import { JettonBalancesDependency } from './dependencies/jettons';
+import { Address } from '@tonkeeper/shared/Address';
+import { StakingDependency } from './dependencies/staking';
+import BigNumber from 'bignumber.js';
+
+export class StakingContentProvider extends ContentProviderPrototype<{
+ tonPrice: TonPriceDependency;
+ jettonBalances: JettonBalancesDependency;
+ staking: StakingDependency;
+}> {
+ name = Providers.Staking;
+ renderPriority = 0;
+
+ constructor(
+ tonPrice: TonPriceDependency,
+ jettonBalances: JettonBalancesDependency,
+ staking: StakingDependency,
+ ) {
+ super({
+ tonPrice,
+ jettonBalances,
+ staking,
+ });
+ }
+
+ private getRate(pool: PoolInfo, info: AccountStakingInfo) {
+ const jettonBalance = this.deps.jettonBalances.state.jettonBalances.find(
+ (balance) =>
+ Address.parse(balance.jettonAddress).toRaw() === pool.liquid_jetton_master,
+ );
+
+ let fiatRate: FiatRate | undefined;
+
+ if (jettonBalance) {
+ fiatRate = this.deps.jettonBalances.getJettonRate(
+ jettonBalance.jettonAddress,
+ jettonBalance.balance,
+ this.deps.tonPrice.state.currency,
+ );
+ } else {
+ fiatRate = this.deps.tonPrice.getFiatRate(
+ formatter.fromNano(info.amount).toString(),
+ );
+ }
+
+ if (!info) {
+ return fiatRate;
+ }
+
+ if (fiatRate && info.pending_deposit) {
+ fiatRate.total.raw = new BigNumber(fiatRate.total.raw)
+ .plus(this.deps.tonPrice.getRawTotal(formatter.fromNano(info.pending_deposit)))
+ .toString();
+ }
+
+ if (fiatRate && info.ready_withdraw) {
+ fiatRate.total.raw = new BigNumber(fiatRate.total.raw)
+ .plus(this.deps.tonPrice.getRawTotal(formatter.fromNano(info.ready_withdraw)))
+ .toString();
+ }
+
+ /**
+ * We should count pending withdraw balance for liquid staking.
+ * But in other cases withdraw is counted in the total balance ¯\_(ツ)_/¯
+ */
+ if (
+ fiatRate &&
+ pool.implementation === PoolImplementationType.LiquidTF &&
+ info.pending_withdraw
+ ) {
+ fiatRate.total.raw = new BigNumber(fiatRate.total.raw)
+ .plus(this.deps.tonPrice.getRawTotal(formatter.fromNano(info.pending_withdraw)))
+ .toString();
+ }
+
+ return fiatRate;
+ }
+
+ get itemsArray() {
+ return this.deps.staking.state.filter((item) => {
+ const info = item.info;
+ if (info) {
+ return true;
+ }
+
+ if ([PoolImplementationType.LiquidTF].includes(item.pool.implementation)) {
+ const stakingJetton = this.deps.jettonBalances.state.jettonBalances.find(
+ (jettonBalance) =>
+ Address.parse(jettonBalance.jettonAddress).toRaw() ===
+ item.pool.liquid_jetton_master,
+ );
+ return stakingJetton && stakingJetton.balance !== '0';
+ }
+ });
+ }
+
+ makeCellItemFromData(data: {
+ info: AccountStakingInfo;
+ pool: PoolInfo;
+ }): CellItemToRender {
+ return {
+ renderPriority: this.renderPriority,
+ RenderComponent: StakingWidgetStatus,
+ passProps: {
+ poolStakingInfo: data.info,
+ pool: data.pool,
+ },
+ fiatRate: this.getRate(data.pool, data.info),
+ key: data.pool.address,
+ title: 'string',
+ subtitle: 'subtitle',
+ value: data.info && formatter.formatNano(data.info.amount),
+ };
+ }
+}
diff --git a/packages/mobile/src/tabs/Wallet/content-providers/tokens.ts b/packages/mobile/src/tabs/Wallet/content-providers/tokens.ts
new file mode 100644
index 000000000..5dd82bc65
--- /dev/null
+++ b/packages/mobile/src/tabs/Wallet/content-providers/tokens.ts
@@ -0,0 +1,76 @@
+import { ContentProviderPrototype } from './utils/prototype';
+import { CellItemToRender } from './utils/types';
+import { formatter } from '$utils/formatter';
+import { JettonBalanceModel } from '$wallet/models/JettonBalanceModel';
+import { openJetton } from '$navigation';
+import { Providers } from './providers';
+import { TonPriceDependency } from './dependencies/tonPrice';
+import { StakingJettonsDependency } from './dependencies/stakingJettons';
+import { TokenApprovalDependency } from './dependencies/tokenApproval';
+import { JettonBalancesDependency } from './dependencies/jettons';
+import { config } from '$config';
+import { JettonVerification } from '$store/models';
+import { t } from '@tonkeeper/shared/i18n';
+import { Steezy } from '$styles';
+
+export class TokensContentProvider extends ContentProviderPrototype<{
+ tonPrice: TonPriceDependency;
+ stakingJettons: StakingJettonsDependency;
+ tokenApproval: TokenApprovalDependency;
+ jettonBalances: JettonBalancesDependency;
+}> {
+ name = Providers.Tokens;
+ renderPriority = 0;
+
+ constructor(
+ tonPrice: TonPriceDependency,
+ stakingJettons: StakingJettonsDependency,
+ tokenApproval: TokenApprovalDependency,
+ jettonBalances: JettonBalancesDependency,
+ ) {
+ super({
+ tonPrice,
+ tokenApproval,
+ stakingJettons,
+ jettonBalances,
+ });
+ }
+
+ get itemsArray() {
+ return this.deps.jettonBalances.state.jettonBalances.filter((jettonBalance) =>
+ [
+ this.deps.stakingJettons.filterTokensBalancesFn,
+ this.deps.tokenApproval.filterTokensBalancesFn,
+ ].every((filterFn) => filterFn(jettonBalance)),
+ );
+ }
+
+ makeCellItemFromData(data: JettonBalanceModel): CellItemToRender {
+ const fiatRate = this.deps.jettonBalances.getJettonRate(
+ data.jettonAddress,
+ data.balance,
+ this.deps.tonPrice.state.currency,
+ );
+ const isUnverifiedToken =
+ !config.get('disable_show_unverified_token') &&
+ data.verification === JettonVerification.NONE;
+
+ return {
+ key: data.jettonAddress,
+ renderPriority: isUnverifiedToken ? -1 : this.renderPriority,
+ title: data.metadata.symbol ?? '',
+ onPress: () => openJetton(data.jettonAddress),
+ fiatRate,
+ picture: data.metadata.image,
+ value: formatter.format(data.balance),
+ subtitleStyle: isUnverifiedToken && styles.unverifiedSubtitleStyle,
+ subtitle: isUnverifiedToken ? t('approval.unverified_token') : undefined,
+ };
+ }
+}
+
+const styles = Steezy.create(({ colors }) => ({
+ unverifiedSubtitleStyle: {
+ color: colors.accentOrange,
+ },
+}));
diff --git a/packages/mobile/src/tabs/Wallet/content-providers/ton.ts b/packages/mobile/src/tabs/Wallet/content-providers/ton.ts
new file mode 100644
index 000000000..d4c41c9c8
--- /dev/null
+++ b/packages/mobile/src/tabs/Wallet/content-providers/ton.ts
@@ -0,0 +1,46 @@
+import { ContentProviderPrototype } from './utils/prototype';
+import { CellItemToRender } from './utils/types';
+import { formatter } from '@tonkeeper/shared/formatter';
+import { openWallet } from '$core/Wallet/ToncoinScreen';
+import { CryptoCurrencies } from '$shared/constants';
+import { Providers } from './providers';
+import { TonPriceDependency } from './dependencies/tonPrice';
+import {
+ TonBalancesDependency,
+ TonBalanceType,
+ TonBalance,
+} from './dependencies/tonBalances';
+
+export const mappedTonBalanceTitle = {
+ [TonBalanceType.Liquid]: 'Toncoin',
+ [TonBalanceType.Locked]: 'Locked Toncoin',
+ [TonBalanceType.Restricted]: 'Restricted Toncoin',
+};
+
+export class TONContentProvider extends ContentProviderPrototype<{
+ tonPrice: TonPriceDependency;
+ tonBalances: TonBalancesDependency;
+}> {
+ name = Providers.TON;
+ renderPriority = 999;
+
+ constructor(tonPrice: TonPriceDependency, tonBalances: TonBalancesDependency) {
+ super({ tonPrice, tonBalances });
+ }
+
+ get itemsArray() {
+ return this.deps.tonBalances.balances;
+ }
+
+ makeCellItemFromData(data: TonBalance): CellItemToRender {
+ return {
+ key: data.type,
+ renderPriority: this.renderPriority,
+ tonIcon: true,
+ fiatRate: this.deps.tonPrice.getFiatRate(data.balance),
+ onPress: () => openWallet(CryptoCurrencies.Ton),
+ title: mappedTonBalanceTitle[data.type],
+ value: formatter.format(data.balance),
+ };
+ }
+}
diff --git a/packages/mobile/src/tabs/Wallet/content-providers/utils/prototype.ts b/packages/mobile/src/tabs/Wallet/content-providers/utils/prototype.ts
new file mode 100644
index 000000000..164fc227d
--- /dev/null
+++ b/packages/mobile/src/tabs/Wallet/content-providers/utils/prototype.ts
@@ -0,0 +1,59 @@
+import { CellItemToRender } from './types';
+import { Wallet } from '$wallet/Wallet';
+import { tk } from '$wallet';
+import { DependencyPrototype } from '../dependencies/utils/prototype';
+
+type Subscriber = () => void;
+
+export type ExternalStateSelector = (
+ state: TStateData,
+) => TSelectedData;
+
+export class ContentProviderPrototype<
+ T extends Record> = {},
+> {
+ public name: string = '';
+ protected renderPriority?: number;
+
+ protected wallet: Wallet = tk.wallet;
+ public subscribers = new Set();
+
+ constructor(protected deps: T = {} as T) {
+ Object.values(deps).map((dep) => {
+ dep.subscribe(() => {
+ this.emitSubscribers();
+ });
+ });
+ }
+
+ protected emitSubscribers() {
+ this.subscribers.forEach((subscriber) => {
+ subscriber();
+ });
+ }
+
+ public subscribe(subscriber: Subscriber) {
+ this.subscribers.add(subscriber);
+ return () => {
+ this.subscribers.delete(subscriber);
+ };
+ }
+
+ get itemsArray(): any[] {
+ return [];
+ }
+
+ get cellItems(): CellItemToRender[] {
+ return this.itemsArray.map((item) => this.makeCellItemFromData(item));
+ }
+
+ makeCellItemFromData(data: any): CellItemToRender {
+ return {
+ key: 'key',
+ renderPriority: this.renderPriority,
+ title: 'title',
+ subtitle: 'subtitle',
+ value: 'value',
+ };
+ }
+}
diff --git a/packages/mobile/src/tabs/Wallet/content-providers/utils/receiver.ts b/packages/mobile/src/tabs/Wallet/content-providers/utils/receiver.ts
new file mode 100644
index 000000000..4179d0282
--- /dev/null
+++ b/packages/mobile/src/tabs/Wallet/content-providers/utils/receiver.ts
@@ -0,0 +1,143 @@
+import { ContentProviderPrototype } from './prototype';
+import debounce from 'lodash/debounce';
+import { TonPriceDependency } from '../dependencies/tonPrice';
+import { TONContentProvider } from '../ton';
+import { TonBalancesDependency } from '../dependencies/tonBalances';
+import { CellItemToRender } from './types';
+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';
+
+type Subscriber = (cells: CellItemToRender[]) => void;
+
+export class WalletContentReceiver {
+ private subscribedTo = new Map void>();
+ private subscribers = new Set();
+
+ private logger: NamespacedLogger;
+
+ 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 memoizedCells = new Map();
+
+ private depsList = [
+ this.tonPrice,
+ this.tonBalances,
+ this.stakingJettons,
+ this.tokenApproval,
+ this.jettonBalances,
+ this.staking,
+ this.inscriptions,
+ ];
+
+ private providersList: ContentProviderPrototype[] = [
+ new TONContentProvider(this.tonPrice, this.tonBalances),
+ new TokensContentProvider(
+ this.tonPrice,
+ this.stakingJettons,
+ this.tokenApproval,
+ this.jettonBalances,
+ ),
+ new StakingContentProvider(this.tonPrice, this.jettonBalances, this.staking),
+ 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');
+ this.depsList.forEach((provider) => {
+ provider.setWallet(wallet);
+ });
+ }
+
+ public sortCellItems(cellItems: CellItemToRender[]): CellItemToRender[] {
+ let content: CellItemToRender[] = cellItems;
+
+ content = content.slice().sort((a, b) => {
+ const comparedPriority = b.renderPriority - a.renderPriority;
+
+ if (comparedPriority !== 0) {
+ return comparedPriority;
+ }
+
+ if (!a.fiatRate && b.fiatRate) {
+ return 1;
+ }
+ if (a.fiatRate && !b.fiatRate) {
+ return -1;
+ }
+
+ if (!a.fiatRate && !b.fiatRate) {
+ return 0;
+ }
+
+ return new BigNumber(b.fiatRate.total.raw).comparedTo(a.fiatRate.total.raw);
+ });
+
+ // Make list; set corners. Mutates objects so we need to copy them
+ if (content[0]) {
+ content[0] = Object.assign({ isFirst: true }, content[0]);
+ content[content.length - 1] = Object.assign(
+ { isLast: true },
+ content[content.length - 1],
+ );
+ }
+
+ return content;
+ }
+
+ get cellItems() {
+ return this.sortCellItems(
+ this.providersList.flatMap((provider) => {
+ const memoized = this.memoizedCells.get(provider.name);
+ if (memoized) {
+ return memoized;
+ }
+ const cellItems = provider.cellItems;
+ this.memoizedCells.set(provider.name, cellItems);
+ return cellItems;
+ }),
+ );
+ }
+
+ private debouncedEmit = debounce(() => {
+ this.subscribers.forEach((subscriber) => {
+ subscriber(this.cellItems);
+ });
+ }, 50);
+
+ private subscribeToProvidersChanges(provider: ContentProviderPrototype[]) {
+ provider.forEach((provider) => {
+ const unsubscribe = provider.subscribe(() => {
+ this.memoizedCells.set(provider.name, false);
+ this.debouncedEmit();
+ });
+ this.subscribedTo.set(provider.name, unsubscribe);
+ });
+ }
+
+ public subscribe(subscriber: Subscriber) {
+ this.subscribers.add(subscriber);
+ return () => {
+ this.subscribers.delete(subscriber);
+ };
+ }
+}
diff --git a/packages/mobile/src/tabs/Wallet/content-providers/utils/types.ts b/packages/mobile/src/tabs/Wallet/content-providers/utils/types.ts
new file mode 100644
index 000000000..165ba9e80
--- /dev/null
+++ b/packages/mobile/src/tabs/Wallet/content-providers/utils/types.ts
@@ -0,0 +1,35 @@
+import { ListItemProps } from '@tonkeeper/uikit/src/components/List/ListItem';
+import { ReactNode } from 'react';
+import { TonIconProps } from '@tonkeeper/uikit';
+
+export type FiatRate = {
+ total: {
+ formatted: string;
+ raw: string;
+ };
+ percent?: string;
+ trend: string;
+ price: {
+ formatted: string;
+ raw: string;
+ };
+};
+
+export type CellItemToRender = {
+ isFirst?: boolean;
+ RenderComponent?: React.JSXElementConstructor;
+ passProps?: Record;
+ isLast?: boolean;
+ key: string;
+ renderPriority: number;
+ subtitleStyle?: ListItemProps['subtitleStyle'];
+ onPress?: () => void;
+ title: string;
+ subtitle?: string;
+ value?: string | ReactNode;
+ subvalue?: string;
+ fiatRate?: FiatRate;
+ picture?: string;
+ tonIcon?: boolean | TonIconProps;
+ tag?: 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
new file mode 100644
index 000000000..8e1bed33d
--- /dev/null
+++ b/packages/mobile/src/tabs/Wallet/content-providers/utils/usePreparedWalletContent.ts
@@ -0,0 +1,30 @@
+import { useEffect, useState } from 'react';
+import { CellItemToRender } from './types';
+import { useInstance } from '$hooks/useInstance';
+import { WalletContentReceiver } from './receiver';
+import { tk } from '$wallet';
+
+export const usePreparedWalletContent = () => {
+ const providersReceiver = useInstance(() => new WalletContentReceiver());
+ const [preparedContent, setPreparedContent] = useState([]);
+
+ useEffect(() => {
+ return tk.onChangeWallet(() => {
+ providersReceiver.setWallet(tk.wallet);
+ });
+ }, [providersReceiver]);
+
+ useEffect(() => {
+ const unsubscribe = providersReceiver.subscribe((cells) => {
+ setPreparedContent(cells);
+ });
+
+ setPreparedContent(providersReceiver.cellItems);
+
+ return () => {
+ unsubscribe();
+ };
+ }, [providersReceiver]);
+
+ return preparedContent;
+};
diff --git a/packages/mobile/src/tabs/Wallet/hooks/useBalance.ts b/packages/mobile/src/tabs/Wallet/hooks/useBalance.ts
index 26878e686..f9a30e3e1 100644
--- a/packages/mobile/src/tabs/Wallet/hooks/useBalance.ts
+++ b/packages/mobile/src/tabs/Wallet/hooks/useBalance.ts
@@ -1,18 +1,8 @@
-import { CryptoCurrencies, Decimals } from '$shared/constants';
-import { useGetTokenPrice, useTokenPrice } from '$hooks/useTokenPrice';
-import { useCallback, useMemo } from 'react';
-import { Ton } from '$libs/Ton';
+import { useMemo } from 'react';
import BigNumber from 'bignumber.js';
import { formatter } from '$utils/formatter';
-import { getStakingJettons } from '@tonkeeper/shared/utils/staking';
-import { Address } from '@tonkeeper/core';
-import {
- useBalancesState,
- useJettons,
- useStakingState,
- useWallet,
- useWalletCurrency,
-} from '@tonkeeper/shared/hooks';
+import { useWalletCurrency } from '@tonkeeper/shared/hooks';
+import { CellItemToRender } from '../content-providers/utils/types';
export type Rate = {
percent: string;
@@ -20,139 +10,19 @@ export type Rate = {
trend: string;
};
-// TODO: rewrite
-const useAmountToFiat = () => {
- const tonPrice = useTokenPrice(CryptoCurrencies.Ton);
- const fiatCurrency = useWalletCurrency();
+export const useBalance = (cellItems: CellItemToRender[]) => {
+ const currency = useWalletCurrency();
- const amountToFiat = useCallback(
- (amount: string, fiatAmountToSum?: number) => {
- if (tonPrice.fiat > 0) {
- const fiat = new BigNumber(amount)
- .multipliedBy(tonPrice.fiat)
- .plus(fiatAmountToSum ?? 0);
- return formatter.format(fiat, { currency: fiatCurrency });
- } else {
- return '-';
- }
- },
- [tonPrice.fiat, fiatCurrency],
- );
+ return useMemo(() => {
+ const totalNumber = cellItems.reduce((total, item) => {
+ const balance = item.fiatRate?.total.raw ?? '0';
+ return total.plus(balance);
+ }, new BigNumber(0));
- return amountToFiat;
-};
-
-const useStakingBalance = () => {
- const _stakingBalance = useStakingState((s) => s.stakingBalance);
- const stakingJettons = useStakingState(getStakingJettons);
- const { jettonBalances } = useJettons();
- const amountToFiat = useAmountToFiat();
- const getTokenPrice = useGetTokenPrice();
-
- const stakingJettonsBalance = useMemo(() => {
- return jettonBalances
- .filter((item) =>
- stakingJettons.includes(Address.parse(item.jettonAddress).toRaw()),
- )
- .reduce((total, jetton) => {
- return total.plus(getTokenPrice(jetton.jettonAddress, jetton.balance).totalTon);
- }, new BigNumber('0'))
- .decimalPlaces(Decimals[CryptoCurrencies.Ton]);
- }, [getTokenPrice, jettonBalances, stakingJettons]);
-
- const stakingBalance = useMemo(() => {
- const balance = new BigNumber(_stakingBalance).plus(stakingJettonsBalance).toString();
- const formatted = formatter.format(balance);
- return {
- amount: {
- nano: balance,
- fiat: amountToFiat(balance),
- formatted,
- },
- };
- }, [_stakingBalance, amountToFiat, stakingJettonsBalance]);
-
- return stakingBalance;
-};
-
-export const useBalance = (tokensTotal: number) => {
- const balances = useBalancesState();
- const wallet = useWallet();
- const amountToFiat = useAmountToFiat();
-
- const stakingBalance = useStakingBalance();
-
- const lockup = useMemo(() => {
- const lockupList: {
- type: CryptoCurrencies;
- amount: {
- nano: string;
- fiat: string;
- formatted: string;
- };
- }[] = [];
-
- if (!wallet.isLockup) {
- return lockupList;
- }
-
- lockupList.push({
- type: CryptoCurrencies.TonRestricted,
- amount: {
- nano: balances.tonRestricted,
- formatted: formatter.format(balances.tonRestricted),
- fiat: amountToFiat(balances.tonRestricted),
- },
- });
-
- lockupList.push({
- type: CryptoCurrencies.TonLocked,
- amount: {
- nano: balances.tonLocked,
- formatted: formatter.format(balances.tonLocked),
- fiat: amountToFiat(balances.tonLocked),
- },
+ return formatter.format(totalNumber.toString(), {
+ currency,
+ forceRespectDecimalPlaces: true,
+ decimals: totalNumber.gte(1000) ? 0 : 2,
});
-
- return lockupList;
- }, [amountToFiat, balances, wallet.isLockup]);
-
- const ton = useMemo(() => {
- const formatted = formatter.format(balances.ton);
- return {
- amount: {
- nano: balances.ton,
- fiat: amountToFiat(balances.ton),
- formatted,
- },
- };
- }, [balances, amountToFiat]);
-
- const total = useMemo(() => {
- const amounts = [ton, stakingBalance, ...lockup];
-
- const balanceNano = amounts
- .reduce((total, balance) => {
- const nano = Ton.toNano(balance.amount.nano);
- return total.plus(nano);
- }, new BigNumber(0))
- .toString(10);
-
- const balance = Ton.fromNano(balanceNano);
-
- return {
- value: balance,
- fiat: amountToFiat(balance, tokensTotal),
- };
- }, [ton, stakingBalance, lockup, amountToFiat, tokensTotal]);
-
- return useMemo(
- () => ({
- lockup,
- total,
- ton,
- staking: stakingBalance,
- }),
- [lockup, total, ton, stakingBalance],
- );
+ }, [cellItems, currency]);
};
diff --git a/packages/mobile/src/uikit/Tag/Tag.tsx b/packages/mobile/src/uikit/Tag/Tag.tsx
index b151dde3d..8ccff22b9 100644
--- a/packages/mobile/src/uikit/Tag/Tag.tsx
+++ b/packages/mobile/src/uikit/Tag/Tag.tsx
@@ -2,7 +2,6 @@ import { Steezy } from '$styles';
import React, { FC, memo } from 'react';
import { View } from '../StyledNativeComponents';
import { StyleSheet } from 'react-native';
-import { TonThemeColor } from '$styled';
import { Text } from '@tonkeeper/uikit';
import { TextColors } from '@tonkeeper/uikit/src/components/Text/Text';
@@ -11,6 +10,7 @@ export type TagType = 'default' | 'accent' | 'warning' | 'warningLight' | 'posit
interface Props {
type?: TagType;
children: string;
+ withLeftSpacing?: boolean;
}
const getTextColor = (type: TagType): TextColors => {
@@ -30,12 +30,12 @@ const getTextColor = (type: TagType): TextColors => {
};
const TagComponent: FC = (props) => {
- const { type = 'default', children } = props;
+ const { type = 'default', children, withLeftSpacing = true } = props;
const textColor = getTextColor(type);
return (
-
+
{children}
@@ -56,6 +56,9 @@ const styles = Steezy.create(({ colors }) => ({
marginLeft: 6,
overflow: 'hidden',
},
+ withoutMargin: {
+ marginLeft: 0,
+ },
background: {
...StyleSheet.absoluteFillObject,
opacity: 0.16,
diff --git a/packages/mobile/src/wallet/AppVault.ts b/packages/mobile/src/wallet/AppVault.ts
index 37f747946..72fc35a60 100644
--- a/packages/mobile/src/wallet/AppVault.ts
+++ b/packages/mobile/src/wallet/AppVault.ts
@@ -57,7 +57,7 @@ export class AppVault implements Vault {
public async import(identifier: string, mnemonic: string, passcode: string) {
try {
- if (!this.decryptedVaultState) {
+ if (Object.keys(this.decryptedVaultState).length === 0) {
this.decryptedVaultState = await this.getDecryptedVaultState(passcode);
}
} catch {}
diff --git a/packages/mobile/src/wallet/Tonkeeper.ts b/packages/mobile/src/wallet/Tonkeeper.ts
index 5bdd475ac..685bb5b1a 100644
--- a/packages/mobile/src/wallet/Tonkeeper.ts
+++ b/packages/mobile/src/wallet/Tonkeeper.ts
@@ -300,14 +300,16 @@ export class Tonkeeper {
{},
);
- const wallets = accounts.map(
- (account, index): ImportWalletInfo => ({
- version: versionByAddress[account.address],
- address: account.address,
- balance: account.balance,
- tokens: accountsJettons[index].balances.length > 0,
- }),
- );
+ const wallets = accounts
+ .map(
+ (account, index): ImportWalletInfo => ({
+ version: versionByAddress[account.address],
+ address: account.address,
+ balance: account.balance,
+ tokens: accountsJettons[index].balances.length > 0,
+ }),
+ )
+ .filter((item) => !!item.version);
if (!wallets.some((wallet) => wallet.version === DEFAULT_WALLET_VERSION)) {
wallets.push({
diff --git a/packages/mobile/src/wallet/Wallet/WalletContent.ts b/packages/mobile/src/wallet/Wallet/WalletContent.ts
index c1fd7c48c..3918274a8 100644
--- a/packages/mobile/src/wallet/Wallet/WalletContent.ts
+++ b/packages/mobile/src/wallet/Wallet/WalletContent.ts
@@ -25,6 +25,7 @@ import { NotificationsManager } from '../managers/NotificationsManager';
import { TonProofManager } from '../managers/TonProofManager';
import { JettonVerification } from '../models/JettonBalanceModel';
import { CardsManager } from '$wallet/managers/CardsManager';
+import { JettonQuantity } from '@tonkeeper/core/src/TonAPI';
export interface WalletStatusState {
isReloading: boolean;
@@ -107,6 +108,7 @@ export class WalletContent extends WalletBase {
this.tonProof,
this.batteryapi,
this.storage,
+ this.isTestnet,
);
this.cards = new CardsManager(
this.persistPath,
@@ -170,6 +172,7 @@ export class WalletContent extends WalletBase {
this.staking.load(),
this.subscriptions.load(),
this.battery.load(),
+ this.battery.loadBatteryConfig(),
this.activityList.load(),
this.cards.load(),
]);
@@ -184,6 +187,7 @@ export class WalletContent extends WalletBase {
this.staking.reload(),
this.subscriptions.reload(),
this.battery.load(),
+ this.battery.loadBatteryConfig(),
this.activityList.reload(),
this.cards.load(),
]);
@@ -205,6 +209,7 @@ export class WalletContent extends WalletBase {
}
const rate =
this.jettons.state.data.jettonRates[Address.parse(jetton.jettonAddress).toRaw()];
+
return rate
? total.plus(new BigNumber(jetton.balance).multipliedBy(rate.fiat))
: total;
@@ -214,4 +219,29 @@ export class WalletContent extends WalletBase {
);
return ton.plus(jettons).plus(staking).toString();
}
+
+ public compareWithTotal(tonBalance: number, jettonBalances: JettonQuantity[]) {
+ const ton = new BigNumber(tonBalance)
+ .shiftedBy(-9)
+ .multipliedBy(this.tonPrice.state.data.ton.fiat);
+ const jettons = jettonBalances.reduce((total, jetton) => {
+ const rate =
+ this.jettons.state.data.jettonRates[Address.parse(jetton.jetton.address).toRaw()];
+
+ const decimalQuantity = new BigNumber(jetton.quantity).shiftedBy(
+ -(jetton.jetton.decimals ?? 9),
+ );
+ return rate
+ ? total.plus(new BigNumber(decimalQuantity).multipliedBy(rate.fiat))
+ : total;
+ }, new BigNumber(0));
+
+ const total = ton.plus(jettons);
+
+ const diff = total.div(this.totalFiat);
+ return {
+ totalFiat: total.toString(),
+ isDangerous: diff.isGreaterThanOrEqualTo('0.2'),
+ };
+ }
}
diff --git a/packages/mobile/src/wallet/constants.ts b/packages/mobile/src/wallet/constants.ts
index 1083e6e0d..abcc0eb7e 100644
--- a/packages/mobile/src/wallet/constants.ts
+++ b/packages/mobile/src/wallet/constants.ts
@@ -5,7 +5,7 @@ import { t } from '@tonkeeper/shared/i18n';
export const DEFAULT_WALLET_STYLE_CONFIG: WalletStyleConfig = {
name: t('wallet_title'),
color: WalletColor.SteelGray,
- emoji: '😀',
+ emoji: 'ic-wallet-32',
};
export const DEFAULT_WALLET_VERSION = WalletContractVersion.v4R2;
diff --git a/packages/mobile/src/wallet/managers/BatteryManager.ts b/packages/mobile/src/wallet/managers/BatteryManager.ts
index 3d408e64d..60867513d 100644
--- a/packages/mobile/src/wallet/managers/BatteryManager.ts
+++ b/packages/mobile/src/wallet/managers/BatteryManager.ts
@@ -4,6 +4,7 @@ import { Storage } from '@tonkeeper/core/src/declarations/Storage';
import { State } from '@tonkeeper/core/src/utils/State';
import { TonProofManager } from '$wallet/managers/TonProofManager';
import { logger, NamespacedLogger } from '$logger';
+import { config } from '$config';
export enum BatterySupportedTransaction {
Swap = 'swap',
@@ -15,6 +16,8 @@ export interface BatteryState {
isLoading: boolean;
balance?: string;
reservedBalance?: string;
+ excessesAccount?: string;
+ fundReceiver?: string;
supportedTransactions: Record;
}
@@ -37,6 +40,7 @@ export class BatteryManager {
private tonProof: TonProofManager,
private batteryapi: BatteryAPI,
private storage: Storage,
+ private isTestnet: boolean,
) {
this.state.persist({
partialize: ({ balance, reservedBalance, supportedTransactions }) => ({
@@ -50,6 +54,14 @@ export class BatteryManager {
this.logger = logger.extend('BatteryManager');
}
+ get excessesAccount() {
+ return this.state.data.excessesAccount;
+ }
+
+ get fundReceiver() {
+ return this.state.data.fundReceiver;
+ }
+
public async fetchBalance() {
try {
if (!this.tonProof.tonProofToken) {
@@ -68,8 +80,7 @@ export class BatteryManager {
this.state.set({
isLoading: false,
balance: data.balance,
- // @ts-expect-error reservedAmount will be implemented in API later. Remove then
- reservedBalance: data.reservedBalance ?? '0',
+ reservedBalance: data.reserved ?? '0',
});
} catch (err) {
this.state.set({ isLoading: false });
@@ -77,21 +88,23 @@ export class BatteryManager {
}
}
- public async getExcessesAccount() {
+ public async loadBatteryConfig() {
try {
if (!this.tonProof.tonProofToken) {
throw new Error('No proof token');
}
-
const data = await this.batteryapi.getConfig({
headers: {
'X-TonConnect-Auth': this.tonProof.tonProofToken,
},
});
- return data.excess_account;
+ return this.state.set({
+ excessesAccount: data.excess_account,
+ fundReceiver: data.fund_receiver,
+ });
} catch (err) {
- return null;
+ this.logger.error(err);
}
}
@@ -220,21 +233,35 @@ export class BatteryManager {
}
}
- public async emulate(boc: string): Promise {
+ public async emulate(
+ boc: string,
+ ): Promise<{ consequences: MessageConsequences; withBattery: boolean }> {
try {
if (!this.tonProof.tonProofToken) {
throw new Error('No proof token');
}
- return await this.batteryapi.emulate.emulateMessageToWallet(
- { boc },
+ const res = await fetch(
+ `${config.get('batteryHost', this.isTestnet)}/wallet/emulate`,
{
+ method: 'POST',
+ body: JSON.stringify({ boc }),
headers: {
+ 'Content-Type': 'application/json',
'X-TonConnect-Auth': this.tonProof.tonProofToken,
},
},
);
+
+ const data: MessageConsequences = await res.json();
+
+ const withBattery =
+ res.headers.get('supported-by-battery') === 'true' &&
+ res.headers.get('allowed-by-battery') === 'true';
+
+ return { consequences: data, withBattery };
} catch (err) {
+ console.log(err);
throw new Error(err);
}
}
diff --git a/packages/mobile/src/wallet/managers/JettonsManager.ts b/packages/mobile/src/wallet/managers/JettonsManager.ts
index 5ac2cc6aa..365ee28ee 100644
--- a/packages/mobile/src/wallet/managers/JettonsManager.ts
+++ b/packages/mobile/src/wallet/managers/JettonsManager.ts
@@ -1,4 +1,4 @@
-import { JettonVerificationType, TonAPI } from '@tonkeeper/core/src/TonAPI';
+import { TonAPI } from '@tonkeeper/core/src/TonAPI';
import { Storage } from '@tonkeeper/core/src/declarations/Storage';
import { TokenRate, TonRawAddress } from '../WalletTypes';
import { Logger } from '@tonkeeper/core/src/utils/Logger';
@@ -7,7 +7,6 @@ import { JettonBalanceModel } from '../models/JettonBalanceModel';
import { Address } from '@tonkeeper/core/src/formatters/Address';
import { TokenApprovalManager } from './TokenApprovalManager';
import { TonPriceManager } from './TonPriceManager';
-import { sortByPrice } from '@tonkeeper/core/src/utils/jettons';
export type JettonsState = {
jettonBalances: JettonBalanceModel[];
@@ -82,31 +81,6 @@ export class JettonsManager {
.filter((item) => {
return item.balance !== '0' || (item.lock && item.lock.amount !== '0');
})
- .sort((a, b) => {
- // Unverified or blacklisted tokens have to be at the end of array
- if (
- [JettonVerificationType.None, JettonVerificationType.Blacklist].includes(
- a.jetton.verification,
- )
- ) {
- return [
- JettonVerificationType.None,
- JettonVerificationType.Blacklist,
- ].includes(b.jetton.verification)
- ? sortByPrice(a, b)
- : 1;
- }
-
- if (
- [JettonVerificationType.None, JettonVerificationType.Blacklist].includes(
- b.jetton.verification,
- )
- ) {
- return -1;
- }
-
- return sortByPrice(a, b);
- })
.map((item) => {
return new JettonBalanceModel(item);
});
diff --git a/packages/mobile/src/wallet/managers/TonInscriptions.ts b/packages/mobile/src/wallet/managers/TonInscriptions.ts
index 0ca121bc6..cc095d288 100644
--- a/packages/mobile/src/wallet/managers/TonInscriptions.ts
+++ b/packages/mobile/src/wallet/managers/TonInscriptions.ts
@@ -2,7 +2,7 @@ import { InscriptionBalance, TonAPI } from '@tonkeeper/core/src/TonAPI';
import { Storage } from '@tonkeeper/core/src/declarations/Storage';
import { State } from '@tonkeeper/core/src/utils/State';
-type TonInscriptionsState = {
+export type TonInscriptionsState = {
items: InscriptionBalance[];
isLoading: boolean;
};
diff --git a/packages/shared/components/ActivityList/PureActionListItem.tsx b/packages/shared/components/ActivityList/PureActionListItem.tsx
new file mode 100644
index 000000000..91f4d5ebb
--- /dev/null
+++ b/packages/shared/components/ActivityList/PureActionListItem.tsx
@@ -0,0 +1,287 @@
+import { openActivityActionModal } from '../../modals/ActivityActionModal';
+import { ActionStatusEnum, JettonVerificationType } from '@tonkeeper/core/src/TonAPI';
+import {
+ Icon,
+ IconNames,
+ List,
+ ListItemContent,
+ ListItemContentText,
+ Loader,
+ Picture,
+ Steezy,
+ Text,
+ View,
+} from '@tonkeeper/uikit';
+import { formatTransactionTime } from '../../utils/date';
+import { findSenderAccount } from './findSenderAccount';
+import { memo, useCallback, useMemo } from 'react';
+import { ImageRequireSource } from 'react-native';
+import { Address } from '../../Address';
+import { t } from '../../i18n';
+
+import { useHideableFormatter } from '@tonkeeper/mobile/src/core/HideableAmount/useHideableFormatter';
+import { useFlags } from '@tonkeeper/mobile/src/utils/flags';
+import { config } from '@tonkeeper/mobile/src/config';
+import { AmountFormatter } from '@tonkeeper/core';
+import {
+ ActionType,
+ AnyActionItem,
+ isJettonTransferAction,
+ ActionSource,
+} from '@tonkeeper/mobile/src/wallet/models/ActivityModel';
+
+export interface ActionListItemProps {
+ onPress?: () => void;
+ subvalue?: string | React.ReactNode;
+ action: AnyActionItem;
+ subtitleNumberOfLines?: number;
+ children?: React.ReactNode;
+ pictureSource?: ImageRequireSource;
+ pictureUri?: string;
+ iconName?: IconNames;
+ leftContent?: React.ReactNode;
+ title?: string;
+ value?: string;
+ subtitle?: string;
+ greenValue?: boolean;
+ ignoreFailed?: boolean;
+ disablePressable?: boolean;
+ disableNftPreview?: boolean;
+ isSimplePreview?: boolean;
+}
+
+export const PureActionListItem = memo((props) => {
+ const {
+ action,
+ children,
+ onPress,
+ subtitleNumberOfLines,
+ greenValue,
+ ignoreFailed,
+ disablePressable,
+ isSimplePreview,
+ } = props;
+ const { formatNano } = useHideableFormatter();
+
+ const isScam =
+ action.event.is_scam ||
+ (isJettonTransferAction(action) &&
+ action.payload.jetton.verification === JettonVerificationType.Blacklist);
+
+ const flags = useFlags(['address_style_nobounce']);
+
+ const bounceable =
+ action.initialActionType === ActionType.SmartContractExec ||
+ !flags.address_style_nobounce;
+
+ const handlePress = useCallback(() => {
+ if (onPress) {
+ onPress();
+ } else {
+ openActivityActionModal(action.action_id, ActionSource.Ton);
+ }
+ }, [onPress]);
+
+ const isFailed = action.status === ActionStatusEnum.Failed;
+
+ const senderAccount = useMemo(() => {
+ return findSenderAccount(action);
+ }, [action]);
+
+ const picture = useMemo(() => {
+ if (props.pictureUri !== undefined) {
+ return { uri: props.pictureUri };
+ } else if (props.pictureSource !== undefined) {
+ return { source: props.pictureSource };
+ } else if (senderAccount?.icon) {
+ return { uri: senderAccount.icon };
+ } else if (action.simple_preview.action_image) {
+ return { uri: action.simple_preview.action_image };
+ } else {
+ return null;
+ }
+ }, [props.pictureSource, props.pictureUri, senderAccount, action.simple_preview]);
+
+ const iconName = useMemo(() => {
+ if (isFailed) {
+ return 'ic-exclamationmark-circle-28';
+ } else if (props.iconName !== undefined) {
+ return props.iconName;
+ } else if (action.destination === 'in') {
+ return 'ic-tray-arrow-down-28';
+ } else if (action.destination === 'out') {
+ return 'ic-tray-arrow-up-28';
+ } else {
+ return 'ic-gear-28';
+ }
+ }, [props.iconName, action, isFailed]);
+
+ const title = useMemo(() => {
+ if (props.title !== undefined) {
+ return props.title;
+ } else if (action.destination === 'in') {
+ return t('transaction_type_receive');
+ } else if (action.destination === 'out') {
+ return t('transaction_type_sent');
+ } else {
+ return action.simple_preview.name;
+ }
+ }, [action.destination, props.title]);
+
+ const subtitle = useMemo(() => {
+ if (isScam) {
+ return t('transactions.spam');
+ } else if (props.subtitle !== undefined) {
+ return props.subtitle;
+ } else if (senderAccount) {
+ if (senderAccount.name) {
+ return senderAccount.name;
+ } else {
+ return Address.parse(senderAccount.address, {
+ bounceable: !senderAccount.is_wallet,
+ }).toShort();
+ }
+ } else {
+ const account = action.simple_preview.accounts[0];
+ return account
+ ? Address.parse(account.address, { bounceable: !account.is_wallet }).toShort()
+ : '-';
+ }
+ }, [action.simple_preview, isScam, senderAccount, props.subtitle, bounceable]);
+
+ const value = useMemo(() => {
+ if (props.value !== undefined) {
+ return props.value;
+ } else {
+ let amountPrefix = AmountFormatter.sign.minus;
+ if (action.type === ActionType.WithdrawStakeRequest) {
+ amountPrefix = '';
+ } else if (action.destination === 'out') {
+ amountPrefix = AmountFormatter.sign.minus;
+ } else if (action.destination === 'in') {
+ amountPrefix = AmountFormatter.sign.plus;
+ }
+
+ if (action.amount) {
+ return formatNano(action.amount.value, {
+ decimals: action.amount.decimals,
+ postfix: action.amount.symbol,
+ prefix: amountPrefix,
+ });
+ }
+
+ return action.simple_preview.value ?? AmountFormatter.sign.minus;
+ }
+ }, [action.destination, action.amount, action.simple_preview, props.value, formatNano]);
+
+ const subvalue = useMemo(() => {
+ if (props.subvalue !== undefined) {
+ return props.subvalue;
+ } else {
+ return formatTransactionTime(new Date(action.event.timestamp * 1000));
+ }
+ }, [action.event.timestamp, props.subvalue]);
+
+ const valueStyle = [
+ (action.destination === 'in' || greenValue) && styles.receiveValue,
+ isScam && styles.scamAmountText,
+ action.type === ActionType.WithdrawStakeRequest && styles.withdrawalRequest,
+ ];
+
+ const leftContent = (
+
+ {picture && !isFailed ? (
+
+ ) : (
+
+ )}
+ {action.event.in_progress && (
+
+
+
+
+
+ )}
+
+ );
+
+ return (
+
+ {!isScam && children}
+ {isSimplePreview && !!action.simple_preview.description && (
+
+ )}
+ {!config.get('disable_show_unverified_token') &&
+ isJettonTransferAction(action) &&
+ action.payload.jetton.verification === JettonVerificationType.None && (
+
+ {t('approval.unverified_token')}
+
+ )}
+ {isFailed && !ignoreFailed && (
+
+ {t('transactions.failed')}
+
+ )}
+
+ );
+});
+
+const styles = Steezy.create(({ colors }) => ({
+ icon: {
+ width: 44,
+ height: 44,
+ borderRadius: 44 / 2,
+ alignItems: 'center',
+ justifyContent: 'center',
+ backgroundColor: colors.backgroundContentTint,
+ },
+ receiveValue: {
+ color: colors.accentGreen,
+ textAlign: 'right',
+ },
+ amount: {
+ textAlign: 'right',
+ marginTop: -3,
+ marginBottom: -1.5,
+ },
+ warn: {
+ marginTop: 8,
+ },
+ scamAmountText: {
+ color: colors.textTertiary,
+ },
+ withdrawalRequest: {
+ color: colors.textTertiary,
+ },
+ sendingOuter: {
+ position: 'absolute',
+ top: -6,
+ left: -6,
+ borderRadius: 18 + 2 / 2,
+ borderWidth: 2,
+ borderColor: colors.backgroundContent,
+ },
+ sendingInner: {
+ borderRadius: 18 / 2,
+ height: 18,
+ width: 18,
+ backgroundColor: colors.iconTertiary,
+ justifyContent: 'center',
+ alignItems: 'center',
+ },
+ picture: {
+ width: 44,
+ height: 44,
+ borderRadius: 44 / 2,
+ },
+}));
diff --git a/packages/shared/components/BatteryIcon/BatteryIcon.tsx b/packages/shared/components/BatteryIcon/BatteryIcon.tsx
index 5080a0842..f13c0b7ea 100644
--- a/packages/shared/components/BatteryIcon/BatteryIcon.tsx
+++ b/packages/shared/components/BatteryIcon/BatteryIcon.tsx
@@ -4,6 +4,7 @@ import {
AnimatedBatteryIcon,
AnimatedBatterySize,
Icon,
+ Spacer,
Steezy,
TouchableOpacity,
} from '@tonkeeper/uikit';
@@ -27,25 +28,28 @@ export const BatteryIcon = memo(() => {
}
return (
-
- {getBatteryState(balance) === BatteryState.Empty ? (
-
- ) : (
-
- )}
-
+ <>
+
+
+ {getBatteryState(balance) === BatteryState.Empty ? (
+
+ ) : (
+
+ )}
+
+ >
);
});
diff --git a/packages/shared/components/RefillBattery/RefillBattery.tsx b/packages/shared/components/RefillBattery/RefillBattery.tsx
index 367c5f395..3d6dfcc19 100644
--- a/packages/shared/components/RefillBattery/RefillBattery.tsx
+++ b/packages/shared/components/RefillBattery/RefillBattery.tsx
@@ -60,7 +60,9 @@ export const RefillBattery = memo((props) => {
{config.get('battery_beta') && (
<>
- Beta
+
+ Beta
+
>
)}
diff --git a/packages/shared/components/RefillBattery/RefillBatteryIAP.tsx b/packages/shared/components/RefillBattery/RefillBatteryIAP.tsx
index 27fee6f61..09c9d46e8 100644
--- a/packages/shared/components/RefillBattery/RefillBatteryIAP.tsx
+++ b/packages/shared/components/RefillBattery/RefillBatteryIAP.tsx
@@ -112,9 +112,13 @@ export const RefillBatteryIAP = memo(() => {
Toast.success(t('battery.refilled'));
setPurchaseInProgress(false);
} catch (e) {
- console.log(e);
setPurchaseInProgress(false);
- Toast.fail(e.message);
+
+ // SKErrorDomain, code=2 - user cancelled. Ignore this error
+ const regEx = /SKErrorDomain,.*2/;
+ if (!regEx.test(e.message)) {
+ Toast.fail(e.message);
+ }
}
},
[],
diff --git a/packages/shared/components/WalletListItem/WalletListItem.tsx b/packages/shared/components/WalletListItem/WalletListItem.tsx
index 7ff2a6984..a22cc1443 100644
--- a/packages/shared/components/WalletListItem/WalletListItem.tsx
+++ b/packages/shared/components/WalletListItem/WalletListItem.tsx
@@ -5,13 +5,13 @@ import {
Steezy,
Text,
View,
+ WalletIcon,
deviceWidth,
getWalletColorHex,
isAndroid,
} from '@tonkeeper/uikit';
import { ListItemProps } from '@tonkeeper/uikit/src/components/List/ListItem';
import { FC, memo } from 'react';
-import { Text as RNText } from 'react-native';
import { t } from '../../i18n';
interface Props extends ListItemProps {
@@ -41,7 +41,11 @@ const WalletListItemComponent: FC = (props) => {
{ backgroundColor: getWalletColorHex(wallet.config.color) },
]}
>
- {wallet.config.emoji}
+
}
{...listItemProps}
diff --git a/packages/shared/i18n/locales/tonkeeper/__snapshots__/id.json b/packages/shared/i18n/locales/tonkeeper/__snapshots__/id.json
index a3b83b842..d318123f8 100644
--- a/packages/shared/i18n/locales/tonkeeper/__snapshots__/id.json
+++ b/packages/shared/i18n/locales/tonkeeper/__snapshots__/id.json
@@ -272,7 +272,7 @@
"confirmSendModal": {
"wallet": "Wallet:",
"refund": "Refund",
- "network_fee": "Network fee",
+ "network_fee": "Fee",
"will_be_paid_with_battery": "Will be paid with Battery",
"title": "Confirm action",
"to_your_address": "To your address",
@@ -628,9 +628,6 @@
"settings_backup_seed": "Recovery Phrase",
"settings_contact_support": "Contact us",
"settings_delete_account": "Delete account",
- "settings_delete_alert_button": "Delete account and data",
- "settings_delete_alert_caption": "This action will delete your account and all data from this application.",
- "settings_delete_alert_title": "Are you sure you want to delete your account?",
"settings_jettons_list": "Tokens",
"settings_legal_documents": "Legal",
"language": {
diff --git a/packages/shared/i18n/locales/tonkeeper/en.json b/packages/shared/i18n/locales/tonkeeper/en.json
index 0de2f1f34..96196eb9d 100644
--- a/packages/shared/i18n/locales/tonkeeper/en.json
+++ b/packages/shared/i18n/locales/tonkeeper/en.json
@@ -299,6 +299,7 @@
"confirm_sending_submit": "Confirm and Send",
"confirm_sending_title": "Confirm sending",
"confirmSendModal": {
+ "total_risk": "Total: %{totalAmount}",
"wallet": "Wallet:",
"refund": "Refund",
"network_fee": "Network fee",
@@ -361,6 +362,7 @@
"edit_coins_title": "Add crypto",
"error_network": "Network error",
"error_occurred": "An error occurred",
+ "network_overloaded_error": "Network overloaded",
"exchange_method_dont_show_again": "Do not show again",
"exchange_method_open_warning": "You are opening an external app not operated by Tonkeeper.",
"exchange_modal": {
@@ -454,6 +456,7 @@
"nft_open_in_marketplace": "View on NFT Market",
"nft_operations_expired": "Request timed out, please try again",
"nft_operation_success": "Done",
+ "nft_operation_slide_to_confirm": "Slide to Confirm",
"nft_owner_address": "Owner",
"nft_price": "Price",
"nft_proceeds": "Your proceeds",
@@ -651,9 +654,6 @@
"settings_backup_seed": "Backup",
"settings_contact_support": "Contact us",
"settings_delete_account": "Delete account",
- "settings_delete_alert_button": "Delete account and data",
- "settings_delete_alert_caption": "This action will delete your account and all data from this application.",
- "settings_delete_alert_title": "\uD83D\uDEA8\uD83D\uDEA8\uD83D\uDEA8%{space}Are you sure you want to delete your account?",
"settings_jettons_list": "Tokens",
"settings_legal_documents": "Legal",
"language": {
@@ -857,7 +857,7 @@
"swap_title": "Swap",
"tab_browser": "Browser",
"tab_nft": "NFTs",
- "tab_settings": "Settings",
+ "tab_collectibles": "Purchases",
"tab_swap": "Swap",
"tab_wallet": "Wallet",
"today": "Today",
@@ -954,7 +954,7 @@
"transaction_wallet_initialized_date": "%{date}",
"transaction_your_bid": "Your bid",
"transfer_pending_by_battery_error": "Another transaction is handling by battery",
- "transfer_deeplink_unknown_jetton_error" : "Unknown token",
+ "transfer_deeplink_unknown_jetton_error": "Unknown token",
"transfer_deeplink_address_error": "Incorrect recipient address",
"transfer_deeplink_unknown_token": "Unknown token",
"transfer_deeplink_wrong_params": "Wrong parameters",
@@ -990,6 +990,7 @@
"stakingFee": "%{count} TON needed for transaction. Estimated fee %{fee} TON will be deducted, the rest will be refunded.",
"stakingDeposit": "Minimum balance for participate:\n%{amount} %{currency}\n",
"title": "Insufficient funds",
+ "title_multiwallet": "Insufficient funds in wallet",
"toBePaid": "To be paid: %{amount} %{currency}\n",
"withFees": "+ blockchain fees.\n",
"yourBalance": "Your balance: %{balance} %{currency}."
@@ -1042,6 +1043,8 @@
"screen_title": "Wallet",
"send_btn": "Send",
"swap_btn": "Swap",
+ "scan_btn": "Scan",
+ "stake_btn": "Stake",
"tonkens_tab_lable": "Tokens",
"updated_at": "Updated on %{value}",
"inscriptions_tab_label": "Inscriptions"
@@ -1202,5 +1205,20 @@
"buy_ton": {
"title": "Buy TON",
"subtitle": "Instantly with a bank card"
+ },
+ "logout_modal": {
+ "title": "Sign Out",
+ "caption": "Wallet keys will be erased from this device.",
+ "delete_title": "Delete Wallet Data",
+ "delete_caption": "Wallet keys and all personal data will be erased from this device.",
+ "agreement": "I have a backup copy of recovery phrase",
+ "backup_button": "Back up",
+ "logout_button": "Sign Out",
+ "delete_button": "Delete Wallet Data"
+ },
+ "about_risk_modal": {
+ "description": "The total value of tokens that will be sent from your wallet. Refunds are not included in the total value.",
+ "description_with_nft": "The total value of tokens, excluding the cost of NFTs, that will be sent from your wallet. Refunds are not included in the total value.",
+ "ok_button": "OK"
}
}
diff --git a/packages/shared/i18n/locales/tonkeeper/id.json b/packages/shared/i18n/locales/tonkeeper/id.json
index 19848e43e..ef7c4bed2 100644
--- a/packages/shared/i18n/locales/tonkeeper/id.json
+++ b/packages/shared/i18n/locales/tonkeeper/id.json
@@ -668,9 +668,6 @@
"settings_backup_seed": "Frasa Pemulihan",
"settings_contact_support": "Hubungi kami",
"settings_delete_account": "Hapus akun",
- "settings_delete_alert_button": "Hapus akun dan data",
- "settings_delete_alert_caption": "Tindakan ini akan menghapus akun Anda dan semua data dari aplikasi ini.",
- "settings_delete_alert_title": "Anda yakin ingin menghapus akun Anda?",
"settings_jettons_list": "Token",
"settings_legal_documents": "Dokumen Hukum",
"settings_network_alert_title": "Pilih jaringan",
diff --git a/packages/shared/i18n/locales/tonkeeper/it.json b/packages/shared/i18n/locales/tonkeeper/it.json
index e4c6f3b70..68a8cec80 100644
--- a/packages/shared/i18n/locales/tonkeeper/it.json
+++ b/packages/shared/i18n/locales/tonkeeper/it.json
@@ -402,9 +402,6 @@
"settings_backup_seed" : "Mostra Frase di Recupero",
"settings_contact_support" : "Contatta il team",
"settings_delete_account" : "Elimina Account",
- "settings_delete_alert_button" : "Elimina Account e Dati",
- "settings_delete_alert_caption" : "Questa azione eliminerà il tuo Account e tutti i Dati da questa applicazione.",
- "settings_delete_alert_title" : "Sei sicuro di voler eliminare il tuo Account?",
"settings_jettons_list" : "Token",
"settings_legal_documents" : "Legale",
"settings_network_alert_title" : "Seleziona rete",
diff --git a/packages/shared/i18n/locales/tonkeeper/ru-RU.json b/packages/shared/i18n/locales/tonkeeper/ru-RU.json
index 961df975d..7046f0ece 100644
--- a/packages/shared/i18n/locales/tonkeeper/ru-RU.json
+++ b/packages/shared/i18n/locales/tonkeeper/ru-RU.json
@@ -238,9 +238,10 @@
"confirm_sending_submit" : "Подтвердить и отправить",
"confirm_sending_title" : "Перевод",
"confirmSendModal" : {
+ "total_risk": "Всего: %{totalAmount}",
"wallet": "Кошелёк:",
"refund": "Возврат",
- "network_fee" : "Комиссия сети",
+ "network_fee" : "Комиссия",
"will_be_paid_with_battery": "Будет оплачена батарейкой",
"title": "Подтвердить действие",
"to_your_address" : "На ваш адрес",
@@ -307,6 +308,7 @@
"edit_coins_title" : "Валюты",
"error_network" : "Ошибка сети",
"error_occurred" : "Произошла ошибка",
+ "network_overloaded_error": "Сеть перегружена",
"exchange_method_dont_show_again" : "Больше не показывать",
"exchange_method_open_warning" : "Вы открываете внешнее приложение, которым не управляет Tonkeeper.",
"exchange_modal" : {
@@ -408,6 +410,7 @@
"nft_open_in_marketplace" : "Посмотреть на NFT Маркете",
"nft_operations_expired" : "Время запроса истекло, попробуйте еще раз",
"nft_operation_success" : "Готово",
+ "nft_operation_slide_to_confirm": "Подтвердить",
"nft_owner_address" : "Владелец",
"nft_price" : "Цена",
"nft_proceeds" : "Ваш доход",
@@ -610,9 +613,6 @@
"settings_backup_seed" : "Резервная копия",
"settings_contact_support" : "Написать команде",
"settings_delete_account" : "Удалить аккаунт",
- "settings_delete_alert_button" : "Удалить аккаунт и данные",
- "settings_delete_alert_caption" : "Это действие приведет к удалению вашего аккаунта и всех данных из этого приложения.",
- "settings_delete_alert_title": "\uD83D\uDEA8\uD83D\uDEA8\uD83D\uDEA8%{space}Вы уверены, что хотите удалить аккаунт?",
"settings_jettons_list" : "Токены",
"settings_legal_documents" : "Юридические документы",
"language": {
@@ -736,7 +736,7 @@
},
"tap_to_collect" : "Нажмите, чтобы вывести"
},
- "estimated_profit" : "%{amount} TON – доход за год,
если внесёте TON сегодня.",
+ "estimated_profit" : "%{amount} TON – доход за год, если внесёте TON сегодня.",
"estimated_profit_compare" : "На %{amount} TON в год прибыльнее чем ваш текущий стейкинг",
"get_withdrawal" : "Получить вывод",
"highest_apy" : "MAX APY",
@@ -845,6 +845,7 @@
"swap_title" : "Обмен",
"tab_browser" : "Браузер",
"tab_nft" : "NFT",
+ "tab_collectibles": "Покупки",
"tab_settings" : "Настройки",
"tab_swap" : "Обмен",
"tab_wallet" : "Кошелёк",
@@ -987,6 +988,7 @@
},
"stakingDeposit" : "Минимальный баланс для участия:\n%{amount} %{currency}\n",
"title" : "Недостаточно средств",
+ "title_multiwallet": "Недостаточно средств на кошельке",
"toBePaid" : "Необходимо: %{amount} %{currency}\n",
"withFees" : "+ комиссия сети.\n",
"yourBalance" : "Ваш баланс: %{balance} %{currency}."
@@ -1039,6 +1041,8 @@
"screen_title" : "Кошелёк",
"send_btn" : "Отправить",
"swap_btn" : "Обменять",
+ "scan_btn": "Сканировать",
+ "stake_btn": "Застейкать",
"tonkens_tab_lable" : "Токены",
"inscriptions_tab_label": "Инскрипции",
"updated_at" : "Обновлён %{value}"
@@ -1181,7 +1185,7 @@
"subtitle": "Отслеживайте активность, получайте уведомления о транзакциях этого кошелька без ввода секретного ключа.",
"wallet_not_found": "Адрес кошелька не найден"
},
- "watch_only": "Только просмотр",
+ "watch_only": "Просмотр",
"stop_watch": "Удалить аккаунт",
"customize": "Кастомизировать",
"customize_modal": {
@@ -1265,5 +1269,20 @@
"buy_ton": {
"title": "Купить TON",
"subtitle": "Моментально с банковской картой"
+ },
+ "logout_modal": {
+ "title": "Выйти",
+ "caption": "Ключи кошелька будут удалены с этого устройства.",
+ "delete_title": "Удалить данные кошелька",
+ "delete_caption": "Ключи кошелька и все личные данные будут удалены с этого устройства.",
+ "agreement": "У меня есть резервная копия фразы восстановления",
+ "backup_button": "Сделать резервную копию",
+ "logout_button": "Выйти",
+ "delete_button": "Удалить данные кошелька"
+ },
+ "about_risk_modal": {
+ "description": "Общая стоимость токенов, которые будут отправлены с вашего кошелька. Возвраты не учитываются в общей стоимости.",
+ "description_with_nft": "Общая стоимость токенов, за исключением стоимости NFT, которые будут отправлены с вашего кошелька. Возвраты не учитываются в общей стоимости.",
+ "ok_button": "Понятно"
}
}
diff --git a/packages/shared/i18n/locales/tonkeeper/tr-TR.json b/packages/shared/i18n/locales/tonkeeper/tr-TR.json
index eed35b047..0086e069d 100644
--- a/packages/shared/i18n/locales/tonkeeper/tr-TR.json
+++ b/packages/shared/i18n/locales/tonkeeper/tr-TR.json
@@ -1,1029 +1,1165 @@
{
- "about_ton" : "TON, Telegram tarafından milyarlarca kullanıcıyı bünyesine katmak için tasarlanmış tamamen merkeziyetsiz bir layer-1 blokzinciridir. TON, ultra hızlı işlem hızına, düşük ücretlere, kullanımı kolay uygulamalara sahiptir ve çevre dostudur.",
- "access_confirmation_logout" : "Oturumu kapat",
- "access_confirmation_reset" : "Sıfırla",
- "access_confirmation_title" : "Şifreyi girin",
- "access_confirmation_update_biometry" : "Biyometrik kimlik doğrulama verilerini kullanmak için şifreyi girin",
- "access_denied" : "Erişim reddedildi",
- "account_deleted" : "Hesap silindi",
- "activityActionModal" : {
- "bid" : "Teklif ver",
- "burned" : "Yakıldı",
- "call_contract" : "Sözleşme çağrısı yap",
- "deposit" : "Yatırma",
- "purchase" : "Satın Al",
- "received" : "Alındı",
- "sent" : "Gönderildi",
- "swapped" : "Takas edildi",
- "time_on" : "İşlem zamanı: %{time}",
- "withdraw" : "Çekme",
- "withdrawal_request" : "Çekme talebi"
+ "about_ton": "TON, Telegram tarafından milyarlarca kullanıcıyı bünyesine katmak için tasarlanmış tamamen merkeziyetsiz bir layer-1 blokzinciridir. TON, ultra hızlı işlem hızına, düşük ücretlere, kullanımı kolay uygulamalara sahiptir ve çevre dostudur.",
+ "access_confirmation_logout": "Oturumu kapat",
+ "access_confirmation_reset": "Sıfırla",
+ "access_confirmation_title": "Şifreyi girin",
+ "access_confirmation_update_biometry": "Biyometrik kimlik doğrulama verilerini kullanmak için şifreyi girin",
+ "access_denied": "Erişim reddedildi",
+ "account_deleted": "Hesap silindi",
+ "activityActionModal": {
+ "bid": "Teklif ver",
+ "burned": "Yakıldı",
+ "call_contract": "Sözleşme çağrısı yap",
+ "deposit": "Yatırma",
+ "purchase": "Satın Al",
+ "received": "Alındı",
+ "sent": "Gönderildi",
+ "swapped": "Takas edildi",
+ "time_on": "İşlem zamanı: %{time}",
+ "withdraw": "Çekme",
+ "withdrawal_request": "Çekme talebi"
},
- "activity" : {
- "buy_toncoin_btn" : "TONcoin satın alın",
- "empty_transaction_caption" : "İlk işleminizi gerçekleştirin!",
- "empty_transaction_title" : "İşleminiz burada gösterilecektir",
- "failed_transaction" : "İşlem başarısız oldu",
- "receive_btn" : "Al",
- "received" : "Alındı",
- "screen_title" : "Etkinlik",
- "sent" : "Gönderildi"
+ "activity": {
+ "buy_toncoin_btn": "TONcoin satın alın",
+ "empty_transaction_caption": "İlk işleminizi gerçekleştirin!",
+ "empty_transaction_title": "İşleminiz burada gösterilecektir",
+ "failed_transaction": "İşlem başarısız oldu",
+ "receive_btn": "Al",
+ "received": "Alındı",
+ "screen_title": "Etkinlik",
+ "sent": "Gönderildi"
},
- "add_edit_favorite" : {
- "address_label" : "Adres",
- "add_title" : "Yeni favori",
- "delete" : "Sil",
- "edit_title" : "Favoriyi düzenle",
- "name_placeholder" : "İsim",
- "save" : "Kaydet"
+ "add_edit_favorite": {
+ "address_label": "Adres",
+ "add_title": "Yeni favori",
+ "delete": "Sil",
+ "edit_title": "Favoriyi düzenle",
+ "name_placeholder": "İsim",
+ "save": "Kaydet"
},
- "add_other_coins" : "Diğer kriptoları ekleyin",
- "address_copied" : "Adres kopyalandı",
- "address_update" : {
- "first_option" : "Muhtemelen hedef cüzdan zaten aktif olarak kullanılıyor olduğundan herhangi bir fark fark etmeyeceksiniz.",
- "learn_more" : "Daha fazla bilgi edinin",
- "new_style" : "Yeni adres",
- "notification_desc_did_change" : "5 Ekim'de cüzdan adresiniz daha iyi bir format olan UQ formatına güncellendi. Eski adresiniz de kullanılmaya devam edeceğinden hiçbir şey yapmanıza gerek bulunmamaktadır.",
- "notification_desc_will_change" : "5 Ekim'de cüzdan adresiniz daha iyi bir format olan UQ formatına güncellenecektir. Eski adresiniz de kullanılmaya devam edeceğinden hiçbir şey yapmanıza gerek bulunmamaktadır.",
- "old_style" : "Eski adres",
- "post_dates" : "\n5 Ekim 2023: Tonkeeper'da tüm adresler UQ formatına geçiş yapacak. 1 Ocak 2024: Tonkeeper, sözleşme durumunu kontrol etmeyi bırakacak ve adresin doğruluğunu kontrol etmek için 'bounceable' bayrağını kullanacak. Bu sayede, EQ adresi ile başlamayan, henüz yayınlanmamış sözleşmelere gönderilen tutarlar göndericiye geri gönderilecektir.",
- "post_rest" : "TON blockchain'de iki adres stili bulunmaktadır ve şimdiye kadar uygulamalar ve cüzdanlar için yalnızca biri kullanılmaktadır. EQ formatı, gelen fonları işleyen akıllı sözleşmeler için en iyi formattır. Bir akıllı sözleşme henüz yayınlanmadıysa - yani kod blokzincirine yüklenmediyse - o adrese gönderilen TON'lar gönderene geri dönecektir. Bu bir güvenlik özelliği olup, herhangi bir hata olduğu taktirde, TON coinlerin geri göndericinin hesabına geri dönmesini sağlar. UQ formatı, cüzdanlar için en iyi formattır. Cüzdanlar sadece fonları saklamak için tasarlandığından, böyle bir durumda gönderilen kripto tutarları asla cüzdana geri dönmez. Her cüzdan, blok zincirinde kod yüklenmiş olmaksızın yalın bir adres olarak kullanılmaya başlandığından, meblağların geri dönmesi anlamsız olur. Bu yıl cüzdan adreslerinde daha uygun format olan UQ formatının kullanımına geçiş yapıyoruz. Eğer size verilen eski bir EQ adresine fon göndermeye devam ederseniz, şu iki seçeneğe sahip olacaksınız;",
- "post_top" : "Bu yılın sonuna kadar TON ağındaki tüm cüzdan adresleri farklı formatlarıyla görüntülenmeye başlanacaktır. Yeni adres UQ ile başlayacak ve son dört harfi değişecektir. Eski adres de kullanılmaya devam edecek olup aynı cüzdana yönlendirecektir. Bu durum cüzdanınızda saklanan kriptoların güvenliğini herhangi bir şekilde etkilemeyecektir.",
- "second_option" : "Cüzdanın herhangi bir ödeme için kullanılmamış olması ihtimali daha azdır. Ve Tonkeeper gelecek yıldan itibaren o adrese coin göndermeyecektir. Alıcından yeni bir UQ adresi istemeniz gerekecektir.",
- "title" : "Adres güncelleme",
- "why_change" : "Bu değişiklik neden yapıldı?",
- "your_wallet" : "Cüzdanınız"
+ "add_other_coins": "Diğer kriptoları ekleyin",
+ "address_copied": "Adres kopyalandı",
+ "address_update": {
+ "first_option": "Muhtemelen hedef cüzdan zaten aktif olarak kullanılıyor olduğundan herhangi bir fark fark etmeyeceksiniz.",
+ "learn_more": "Daha fazla bilgi edinin",
+ "new_style": "Yeni adres",
+ "notification_desc_did_change": "5 Ekim'de cüzdan adresiniz daha iyi bir format olan UQ formatına güncellendi. Eski adresiniz de kullanılmaya devam edeceğinden hiçbir şey yapmanıza gerek bulunmamaktadır.",
+ "notification_desc_will_change": "5 Ekim'de cüzdan adresiniz daha iyi bir format olan UQ formatına güncellenecektir. Eski adresiniz de kullanılmaya devam edeceğinden hiçbir şey yapmanıza gerek bulunmamaktadır.",
+ "old_style": "Eski adres",
+ "post_dates": "\n5 Ekim 2023: Tonkeeper'da tüm adresler UQ formatına geçiş yapacak. 1 Ocak 2024: Tonkeeper, sözleşme durumunu kontrol etmeyi bırakacak ve adresin doğruluğunu kontrol etmek için 'bounceable' bayrağını kullanacak. Bu sayede, EQ adresi ile başlamayan, henüz yayınlanmamış sözleşmelere gönderilen tutarlar göndericiye geri gönderilecektir.",
+ "post_rest": "TON blockchain'de iki adres stili bulunmaktadır ve şimdiye kadar uygulamalar ve cüzdanlar için yalnızca biri kullanılmaktadır. EQ formatı, gelen fonları işleyen akıllı sözleşmeler için en iyi formattır. Bir akıllı sözleşme henüz yayınlanmadıysa - yani kod blokzincirine yüklenmediyse - o adrese gönderilen TON'lar gönderene geri dönecektir. Bu bir güvenlik özelliği olup, herhangi bir hata olduğu taktirde, TON coinlerin geri göndericinin hesabına geri dönmesini sağlar. UQ formatı, cüzdanlar için en iyi formattır. Cüzdanlar sadece fonları saklamak için tasarlandığından, böyle bir durumda gönderilen kripto tutarları asla cüzdana geri dönmez. Her cüzdan, blok zincirinde kod yüklenmiş olmaksızın yalın bir adres olarak kullanılmaya başlandığından, meblağların geri dönmesi anlamsız olur. Bu yıl cüzdan adreslerinde daha uygun format olan UQ formatının kullanımına geçiş yapıyoruz. Eğer size verilen eski bir EQ adresine fon göndermeye devam ederseniz, şu iki seçeneğe sahip olacaksınız;",
+ "post_top": "Bu yılın sonuna kadar TON ağındaki tüm cüzdan adresleri farklı formatlarıyla görüntülenmeye başlanacaktır. Yeni adres UQ ile başlayacak ve son dört harfi değişecektir. Eski adres de kullanılmaya devam edecek olup aynı cüzdana yönlendirecektir. Bu durum cüzdanınızda saklanan kriptoların güvenliğini herhangi bir şekilde etkilemeyecektir.",
+ "second_option": "Cüzdanın herhangi bir ödeme için kullanılmamış olması ihtimali daha azdır. Ve Tonkeeper gelecek yıldan itibaren o adrese coin göndermeyecektir. Alıcından yeni bir UQ adresi istemeniz gerekecektir.",
+ "title": "Adres güncelleme",
+ "why_change": "Bu değişiklik neden yapıldı?",
+ "your_wallet": "Cüzdanınız"
},
- "all_regions" : "Tüm bölgeler",
- "appearance_accent_name" : {
- "andromeda" : "Andromeda",
- "arctic" : "Arctic",
- "azure" : "Azure",
- "coral" : "Coral",
- "cosmos" : "Cosmos",
- "default" : "Tonkeeper",
- "flamingo" : "Flamingo",
- "fluid" : "Fluid",
- "galaxy" : "Galaxy",
- "iris" : "Iris",
- "marine" : "Marine",
- "ocean" : "Ocean",
- "sky" : "Sky"
+ "add_wallet": "Cüzdan Ekle",
+ "add_wallet_modal": {
+ "create": {
+ "subtitle": "Yeni cüzdan oluşturun",
+ "title": "Yeni Cüzdan"
+ },
+ "import": {
+ "subtitle": "24 gizli kurtarma kelimesiyle cüzdanı içe aktarın",
+ "title": "Mevcut Cüzdan"
+ },
+ "subtitle": "Yeni bir cüzdan oluşturun veya mevcut bir cüzdan ekleyin.",
+ "testnet": {
+ "subtitle": "24 gizli kurtarma kelimesi içeren cüzdanı Testnet'e aktarın",
+ "title": "Testnet Hesabı"
+ },
+ "title": "Cüzdan Ekle",
+ "watch_only": {
+ "subtitle": "Kurtarma ifadesi olmadan cüzdan etkinliğini izlemek için",
+ "title": "Hesabı İzle"
+ }
+ },
+ "add_watch_only": {
+ "subtitle": "Kurtarma ifadesi olmadan cüzdan etkinliğini izleyin. Bu cüzdandan yapılan tüm işlemler size bildirilecektir.",
+ "title": "Hesabı İzle",
+ "wallet_not_found": "Cüzdan adresi bulunamadı"
+ },
+ "all_regions": "Tüm bölgeler",
+ "appearance_accent_name": {
+ "andromeda": "Andromeda",
+ "arctic": "Arctic",
+ "azure": "Azure",
+ "coral": "Coral",
+ "cosmos": "Cosmos",
+ "default": "Tonkeeper",
+ "flamingo": "Flamingo",
+ "fluid": "Fluid",
+ "galaxy": "Galaxy",
+ "iris": "Iris",
+ "marine": "Marine",
+ "ocean": "Ocean",
+ "sky": "Sky"
+ },
+ "appearance_confirm": "Ayarla",
+ "appearance_description": "TON Diamonds NFT, cüzdanınızı daha renkli ve benzersiz hale getirecektir.",
+ "appearance_title": "Tema",
+ "app_name": "Tonkeeper",
+ "approval": {
+ "accept": "Onaylayın",
+ "accepted": "Onaylandı",
+ "accepted_at_collection": "%{date} tarihinde onaylandı",
+ "accepted_at_token": "%{date} tarihinde onaylandı",
+ "accepted_collection": "Kabul edilen koleksiyon",
+ "accepted_token": "Kabul edilen token",
+ "approve_all": "Tümünü onayla",
+ "approve_collection_many": "\"%{collection}\" koleksiyonundan gelen token'ları onaylayın",
+ "approve_collection_one": "\"%{collection}\" koleksiyonundan gelen token'ı onaylayın",
+ "approve_many": "Gelen %{count} token'ı onaylayın",
+ "approve_token": "Gelen \"%{name}\" token'ını onaylayın",
+ "approve_two_collections": "\"%{collection1}\" \"%{collection2}\" koleksiyonlarından gelen token'ları onaylayın",
+ "approve_two_tokens": "Gelen \"%{name1}\" ve \"%{name2}\" token'larını onaylayın",
+ "blacklisted_collection": "Kara listeye alınmış koleksiyon",
+ "blacklisted_token": "Kara listeye alınmış token",
+ "decline": "Reddet",
+ "declined": "Reddedildi",
+ "declined_at_collection": "%{date} tarihinde reddedildi",
+ "declined_at_token": "%{date} tarihinde reddedildi",
+ "details_collection": "Koleksiyon detayları",
+ "details_token": "Token detayları",
+ "id_collection": "Koleksiyon Kimliği",
+ "id_token": "Token Kimliği",
+ "manage_tokens": "Token'ları yönetin",
+ "move_to_accepted": "Onaylananlar'a taşıyın",
+ "move_to_accepted_collection": "Koleksiyonu cüzdanda göster",
+ "move_to_accepted_token": "Cüzdandaki token'ları göster",
+ "move_to_declined": "Reddedilenler'e taşıyın",
+ "move_to_declined_collection": "Koleksiyonu cüzdanda gizle",
+ "move_to_declined_token": "Token'ı cüzdanda gizle",
+ "name": "İsim",
+ "pending": "Beklemede",
+ "show_all": "Tümünü göster",
+ "single_token": "Tek token",
+ "token_copied": "Token kimliği kopyalandı",
+ "token_count": {
+ "one": "%{count} token",
+ "other": "%{count} token"
+ },
+ "unverified_token": "Doğrulanmamış Token",
+ "verify_collection": "Koleksiyonu doğrulayın",
+ "verify_description_collection": "Bu token'lar bilinmeyen bir token yayıncısı tarafından basılmış. Token'ların sahtelerini tespit etmek için, token yayıncının resmi kaynağıyla karşılaştırarak koleksiyon kimliğini doğrulayın. Token görünürlüğünü daha sonra ayarlar içerisinden değiştirebilirsiniz.",
+ "verify_description_token": "Bu token bilinmeyen bir token yayıncısı tarafından basılmış. Token'ların sahtelerini tespit etmek için, token yayıncının resmi kaynağıyla karşılaştırarak token kimliğini doğrulayın. Token görünürlüğünü daha sonra ayarlar içerisinden değiştirebilirsiniz.",
+ "verify_token": "Token'i doğrulayın",
+ "whitelisted_collection": "Beyaz listeye alınmış koleksiyon",
+ "whitelisted_token": "Beyaz listeye alınmış token"
+ },
+ "auth_failed": "Kimlik doğrulama başarısız oldu",
+ "backup_check": {
+ "caption": "Her şeyi doğru yapıp yapmadığınızı görelim. %{one}, %{two} ve %{three} numaralı kelimeleri girin.",
+ "done_button": "Tamamlandı",
+ "title": "Yedekleme Kontrolü"
+ },
+ "backup_screen": {
+ "last_backup_time": "Son yedekleme %{time}",
+ "manual_backup_on": "Manuel Yedekleme Açık",
+ "manual_button": "Manuel Olarak Yedekleyin",
+ "manual_caption": "Kurtarma ifadesini yazarak cüzdanınızı manuel olarak yedekleyin.",
+ "manual_title": "Manuel",
+ "show_recovery_phrase": "Kurtarma İfadesini Göster",
+ "title": "Yedekle"
+ },
+ "backup_warning": {
+ "cancel_button": "İptal",
+ "caption": "Kurtarma ifadenizi görüntülemeden önce lütfen aşağıdakileri dikkatlice okuyun.",
+ "continue_button": "Devam et",
+ "p1": "Cüzdanınıza erişmek için kurtarma cümlenizi asla Tonkeeper'dan başka bir yere girmeyin.",
+ "p2": "Tonkeeper Destek hiçbir zaman size kurtarma ifadesini sormaz.",
+ "p3": "Kurtarma ifadenizi bilen herkes cüzdanınıza erişebilir.",
+ "title": "Dikkat"
},
- "appearance_confirm" : "Ayarla",
- "appearance_description" : "TON Diamonds NFT, cüzdanınızı daha renkli ve benzersiz hale getirecektir.",
- "appearance_title" : "Tema",
- "app_name" : "Tonkeeper",
- "approval" : {
- "accept" : "Onaylayın",
- "accepted" : "Onaylandı",
- "accepted_at_collection" : "%{date} tarihinde onaylandı",
- "accepted_at_token" : "%{date} tarihinde onaylandı",
- "accepted_collection" : "Kabul edilen koleksiyon",
- "accepted_token" : "Kabul edilen token",
- "approve_all" : "Tümünü onayla",
- "approve_collection_many" : "\"%{collection}\" koleksiyonundan gelen token'ları onaylayın",
- "approve_collection_one" : "\"%{collection}\" koleksiyonundan gelen token'ı onaylayın",
- "approve_many" : "Gelen %{count} token'ı onaylayın",
- "approve_token" : "Gelen \"%{name}\" token'ını onaylayın",
- "approve_two_collections" : "\"%{collection1}\" \"%{collection2}\" koleksiyonlarından gelen token'ları onaylayın",
- "approve_two_tokens" : "Gelen \"%{name1}\" ve \"%{name2}\" token'larını onaylayın",
- "blacklisted_collection" : "Kara listeye alınmış koleksiyon",
- "blacklisted_token" : "Kara listeye alınmış token",
- "decline" : "Reddet",
- "declined" : "Reddedildi",
- "declined_at_collection" : "%{date} tarihinde reddedildi",
- "declined_at_token" : "%{date} tarihinde reddedildi",
- "details_collection" : "Koleksiyon detayları",
- "details_token" : "Token detayları",
- "id_collection" : "Koleksiyon Kimliği",
- "id_token" : "Token Kimliği",
- "manage_tokens" : "Token'ları yönetin",
- "move_to_accepted" : "Onaylananlar'a taşıyın",
- "move_to_accepted_collection" : "Koleksiyonu cüzdanda göster",
- "move_to_accepted_token" : "Cüzdandaki token'ları göster",
- "move_to_declined" : "Reddedilenler'e taşıyın",
- "move_to_declined_collection" : "Koleksiyonu cüzdanda gizle",
- "move_to_declined_token" : "Token'ı cüzdanda gizle",
- "name" : "İsim",
- "pending" : "Beklemede",
- "show_all" : "Tümünü göster",
- "single_token" : "Tek token",
- "token_copied" : "Token kimliği kopyalandı",
- "token_count" : {
- "one" : "%{count} token",
- "other" : "%{count} token"
+ "balances_setup_wallet": "Cüzdanı ayarlayın",
+ "battery": {
+ "description": {
+ "empty": "Ana bakiyeniz boş olsa bile token ve NFT gönderin, staking işlemleri gerçekleştirin.",
+ "other": "%{cnt} işlem için bataryanızda yeterli şarj seviyesi mevcut."
},
- "unverified_token" : "Doğrulanmamış Token",
- "verify_collection" : "Koleksiyonu doğrulayın",
- "verify_description_collection" : "Bu token'lar bilinmeyen bir token yayıncısı tarafından basılmış. Token'ların sahtelerini tespit etmek için, token yayıncının resmi kaynağıyla karşılaştırarak koleksiyon kimliğini doğrulayın. Token görünürlüğünü daha sonra ayarlar içerisinden değiştirebilirsiniz.",
- "verify_description_token" : "Bu token bilinmeyen bir token yayıncısı tarafından basılmış. Token'ların sahtelerini tespit etmek için, token yayıncının resmi kaynağıyla karşılaştırarak token kimliğini doğrulayın. Token görünürlüğünü daha sonra ayarlar içerisinden değiştirebilirsiniz.",
- "verify_token" : "Token'i doğrulayın",
- "whitelisted_collection" : "Beyaz listeye alınmış koleksiyon",
- "whitelisted_token" : "Beyaz listeye alınmış token"
+ "ok": "TAMAM",
+ "packages": {
+ "buy": "Satın al",
+ "disclaimer": "Bu yaklaşık işlem sayısıdır. Bazı işlemlerinizin maliyeti daha yüksek olabilir.",
+ "ok": "TAMAM",
+ "refilled": "Bataryanız şarj oldu"
+ },
+ "promocode": {
+ "apply": "Uygula",
+ "button": "Promosyon Kodu ile yükleme yapın",
+ "placeholder": "Kod",
+ "success": "Bataryanız şarj oldu",
+ "title": "Promosyon Kodu"
+ },
+ "screen_title": "Batarya",
+ "settings": "Batarya"
+ },
+ "biometry": {
+ "android": {
+ "face_recognition": "yüz tanıma",
+ "face_recognition_genitive": "yüz tanıma",
+ "face_recognition_instrumental": "yüz tanıma",
+ "fingerprint": "Parmak izi",
+ "fingerprint_genitive": "Parmak izi",
+ "fingerprint_instrumental": "Parmak izi"
+ },
+ "default": "Biyometrik",
+ "default_accusative": "Biyometrik",
+ "default_genitive": "Biyometrik",
+ "default_instrumental": "Biyometrik",
+ "ios": {
+ "face_recognition": "Yüz kimliği",
+ "face_recognition_genitive": "Yüz kimliği",
+ "face_recognition_instrumental": "Face ID",
+ "fingerprint": "Touch ID",
+ "fingerprint_genitive": "Touch ID",
+ "fingerprint_instrumental": "Touch ID"
+ }
},
- "auth_failed" : "Kimlik doğrulama başarısız oldu",
- "balances_setup_wallet" : "Cüzdanı ayarlayın",
- "browser" : {
- "about_dapps_caption" : "Oturum açma ve ödemeler için Tonkeeper'ı kullanabileceğiniz uygulamaları ve hizmetleri keşfedin.",
- "about_dapps_learn_more" : "Daha fazla bilgi edinin",
- "about_dapps_title" : "Tüm TON uygulamaları ve hizmetleriyle Tonkeeper'ı kullanın",
- "actions" : {
- "copy_link" : "Bağlantıyı kopyalayın",
- "disconnect" : "Bağlantıyı kesin",
- "mute" : "Sessize alın",
- "refresh" : "Yenileyin",
- "share" : "Paylaşın"
+ "browser": {
+ "about_dapps_caption": "Oturum açma ve ödemeler için Tonkeeper'ı kullanabileceğiniz uygulamaları ve hizmetleri keşfedin.",
+ "about_dapps_learn_more": "Daha fazla bilgi edinin",
+ "about_dapps_title": "Tüm TON uygulamaları ve hizmetleriyle Tonkeeper'ı kullanın",
+ "actions": {
+ "copy_link": "Bağlantıyı kopyalayın",
+ "disconnect": "Bağlantıyı kesin",
+ "mute": "Sessize alın",
+ "refresh": "Yenileyin",
+ "share": "Paylaşın"
},
- "apps_all" : "Tümü",
- "connected" : "Bağlı",
- "connected_empty_text" : "Uygulamaları ve hizmetleri Tonkeeper tarayıcısında keşfedin.",
- "connected_empty_title" : "Bağlı uygulamalar burada gösterilecektir",
- "connected_title" : "Bağlandı",
- "empty_search" : "Aramanız hiçbir sonuç vermedi",
- "explore" : "Keşfet",
- "explore_all" : "Tümünü keşfedin",
- "more_description" : "Marketler, borsalar ve daha fazlası",
- "more_title" : "Tüm hizmetleri keşfedin",
- "open_link" : "Bağlantıyı açın",
- "popular_title" : "Popüler",
- "remove_alert" : {
- "approve_button" : "Kaldırın",
- "title" : "“%{name}” kaldırılsın mı?"
+ "apps_all": "Tümü",
+ "connected": "Bağlı",
+ "connected_empty_text": "Uygulamaları ve hizmetleri Tonkeeper tarayıcısında keşfedin.",
+ "connected_empty_title": "Bağlı uygulamalar burada gösterilecektir",
+ "connected_title": "Bağlandı",
+ "empty_search": "Aramanız hiçbir sonuç vermedi",
+ "explore": "Keşfet",
+ "explore_all": "Tümünü keşfedin",
+ "more_description": "Marketler, borsalar ve daha fazlası",
+ "more_title": "Tüm hizmetleri keşfedin",
+ "open_link": "Bağlantıyı açın",
+ "popular_title": "Popüler",
+ "remove_alert": {
+ "approve_button": "Kaldırın",
+ "title": "“%{name}” kaldırılsın mı?"
},
- "search_label" : "Adresi arayın ya da girin",
- "start_typing" : "Bir adres girin veya web'de arama yapın",
- "title" : "Tarayıcı",
- "web_search_title" : "%{searchEngine} Arama"
+ "search_label": "Adresi arayın ya da girin",
+ "start_typing": "Bir adres girin veya web'de arama yapın",
+ "title": "Tarayıcı",
+ "web_search_title": "%{searchEngine} Arama"
},
- "cancel" : "İptal",
- "chart" : {
- "check_connection" : "Lütfen bağlantınızı kontrol edin ve tekrar deneyin.",
- "no_internet" : "İnternet bağlantısı yok",
- "periods" : {
- "1D" : "G",
- "1H" : "H",
- "1M" : "A",
- "1Y" : "Y",
- "6M" : "6 Ay",
- "7D" : "H"
+ "cancel": "İptal",
+ "chart": {
+ "check_connection": "Lütfen bağlantınızı kontrol edin ve tekrar deneyin.",
+ "no_internet": "İnternet bağlantısı yok",
+ "periods": {
+ "1D": "G",
+ "1H": "H",
+ "1M": "A",
+ "1Y": "Y",
+ "6M": "6 Ay",
+ "7D": "H"
},
- "price" : "Fiyat"
+ "price": "Fiyat"
},
- "check_words_caption" : "Kurtarma ifadenizi doğru yazıp yazmadığınızı kontrol etmek için lütfen %{wordNum1}, %{wordNum2} ve %{wordNum3} numaralı kelimeleri girin.",
- "check_words_success" : "Tebrikler! Cüzdan kurulumunuzu tamamladınız",
- "check_words_title" : "Haydi şimdi kontrol edelim",
- "choose_country" : {
- "auto" : "Otomatik",
- "cancel" : "İptal",
- "empty_placeholder" : "Aramanız hiçbir sonuç vermedi",
- "search" : "Arama",
- "title" : "Ülkenizi seçin"
+ "check_words_caption": "Kurtarma ifadenizi doğru yazıp yazmadığınızı kontrol etmek için lütfen %{wordNum1}, %{wordNum2} ve %{wordNum3} numaralı kelimeleri girin.",
+ "check_words_success": "Tebrikler! Cüzdan kurulumunuzu tamamladınız",
+ "check_words_title": "Haydi şimdi kontrol edelim",
+ "choose_country": {
+ "auto": "Otomatik",
+ "cancel": "İptal",
+ "empty_placeholder": "Aramanız hiçbir sonuç vermedi",
+ "search": "Arama",
+ "title": "Ülkenizi seçin"
},
- "choose_currency" : {
- "currencies" : {
- "AED" : "Birleşik Arap Emirlikleri dirhemi",
- "BDT" : "Bangladeş takası",
- "BRL" : "Brezilya reali",
- "BYN" : "Belarus rublesi",
- "CAD" : "Kanada doları",
- "CHF" : "İsviçre frangı",
- "CNY" : "Çin yuanı",
- "EUR" : "Euro",
- "GBP" : "İngiliz sterlini",
- "GEL" : "Gürcistan larisi",
- "IDR" : "Endonezya rupisi",
- "ILS" : "İsrail şekeli",
- "INR" : "Hint rupisi",
- "IRR" : "İran riyali",
- "JPY" : "Japon yeni",
- "KRW" : "Güney Kore wonu",
- "KZT" : "Kazakistan tengesi",
- "NGN" : "Nijerya nairası",
- "RUB" : "Rus rublesi",
- "THB" : "Tayland bahtı",
- "TON" : "Toncoin",
- "TRY" : "Türk lirası",
- "UAH" : "Ukrayna hryvnyası",
- "USD" : "Amerikan doları",
- "UZS" : "Özbekistan somu",
- "VND" : "Vietnam dongu"
+ "choose_currency": {
+ "currencies": {
+ "AED": "Birleşik Arap Emirlikleri dirhemi",
+ "BDT": "Bangladeş takası",
+ "BRL": "Brezilya reali",
+ "BYN": "Belarus rublesi",
+ "CAD": "Kanada doları",
+ "CHF": "İsviçre frangı",
+ "CNY": "Çin yuanı",
+ "EUR": "Euro",
+ "GBP": "İngiliz sterlini",
+ "GEL": "Gürcistan larisi",
+ "IDR": "Endonezya rupisi",
+ "ILS": "İsrail şekeli",
+ "INR": "Hint rupisi",
+ "IRR": "İran riyali",
+ "JPY": "Japon yeni",
+ "KRW": "Güney Kore wonu",
+ "KZT": "Kazakistan tengesi",
+ "NGN": "Nijerya nairası",
+ "RUB": "Rus rublesi",
+ "THB": "Tayland bahtı",
+ "TON": "Toncoin",
+ "TRY": "Türk lirası",
+ "UAH": "Ukrayna hryvnyası",
+ "USD": "Amerikan doları",
+ "UZS": "Özbekistan somu",
+ "VND": "Vietnam dongu"
},
- "header_title" : "Birincil para birimi"
+ "header_title": "Birincil para birimi"
+ },
+ "choose_wallets": {
+ "subtitle": "Eklemek istediğiniz cüzdanları seçin.",
+ "title": "Cüzdanları Seçin",
+ "tokens": "Token'lar"
},
- "confirm" : "Onaylayın",
- "confirm_renew_all_domains_title" : "İşlemi onaylayın",
- "confirm_sending_amount" : "Tutar",
- "confirm_sending_fee" : "Ücret",
- "confirm_sending_inactive_warn_about" : "Ne yapmalısınız?",
- "confirm_sending_inactive_warn_description" : "Eğer blok zincirinin sihir gerçekleştirmesini bekliyorsanız devam etmeyin. Çünkü böyle bir şey olmayacak.",
- "confirm_sending_inactive_warn_title" : "Etkin olmayan sözleşme",
- "confirm_sending_liquid_warn_description" : "Artık gönderilen stake edilmiş TON coin'lerden ödül almayacaksınız. Bu coin'lerin yeni sahibi ödülleri almaya başlayacak.",
- "confirm_sending_liquid_warn_title" : "Not",
- "confirm_sending_message" : "Yorum",
- "confirm_sending_method_title" : "Kriptolarınızı %{name}'e göndermek istiyor musunuz?",
- "confirm_sending_recipient" : "Alıcı",
- "confirm_sending_recipient_address" : "Alıcı adresi",
- "confirm_sending_sent_caption_btc" : "İşleminiz ağa gönderildi ve bir saat içinde işleme alınacak.",
- "confirm_sending_sent_caption_ton" : "İşleminiz ağa gönderildi ve bir kaç saniye içinde işleme alınacak.",
- "confirm_sending_submit" : "Onaylayın ve Gönderin",
- "confirm_sending_title" : "Göndermeyi onaylayın",
- "confirmSendModal" : {
- "network_fee" : "Ağ ücreti",
- "refund" : "İade",
- "title" : "İşlemi onaylayın",
- "to_your_address" : "Adresinize",
- "transaction_type" : {
- "burn" : "Yak",
- "receive" : "Al",
- "send" : "Gönder"
+ "confirm": "Onaylayın",
+ "confirm_renew_all_domains_title": "İşlemi onaylayın",
+ "confirm_sending_amount": "Tutar",
+ "confirm_sending_fee": "Ücret",
+ "confirm_sending_inactive_warn_about": "Ne yapmalısınız?",
+ "confirm_sending_inactive_warn_description": "Eğer blok zincirinin sihir gerçekleştirmesini bekliyorsanız devam etmeyin. Çünkü böyle bir şey olmayacak.",
+ "confirm_sending_inactive_warn_title": "Etkin olmayan sözleşme",
+ "confirm_sending_liquid_warn_description": "Artık gönderilen stake edilmiş TON coin'lerden ödül almayacaksınız. Bu coin'lerin yeni sahibi ödülleri almaya başlayacak.",
+ "confirm_sending_liquid_warn_title": "Not",
+ "confirm_sending_message": "Yorum",
+ "confirm_sending_method_title": "Kriptolarınızı %{name}'e göndermek istiyor musunuz?",
+ "confirm_sending_recipient": "Alıcı",
+ "confirm_sending_recipient_address": "Alıcı adresi",
+ "confirm_sending_sent_caption_btc": "İşleminiz ağa gönderildi ve bir saat içinde işleme alınacak.",
+ "confirm_sending_sent_caption_ton": "İşleminiz ağa gönderildi ve bir kaç saniye içinde işleme alınacak.",
+ "confirm_sending_submit": "Onaylayın ve Gönderin",
+ "confirm_sending_title": "Göndermeyi onaylayın",
+ "confirmSendModal": {
+ "network_fee": "Ağ ücreti",
+ "refund": "İade",
+ "title": "İşlemi onaylayın",
+ "to_your_address": "Adresinize",
+ "transaction_type": {
+ "burn": "Yak",
+ "receive": "Al",
+ "send": "Gönder"
},
- "will_be_paid_with_battery" : "Batarya ile ödenecek"
+ "wallet": "Cüzdan:",
+ "will_be_paid_with_battery": "Batarya ile ödenecek"
},
- "continue" : "Devam et",
- "copied" : "Kopyalandı",
- "copy_error_log" : "Hata kaydını kopyalayın",
- "create_pin_current_title" : "Mevcut şifreyi girin",
- "create_pin_new_title" : "Yeni şifre oluşturun",
- "create_pin_repeat_title" : "Şifreyi tekrar girin",
- "create_wallet_caption" : "Cihazınızı kaybetmeniz durumunda cüzdanınıza erişmenin ve hesabınızı kurtarmanın tek yolu olduğu için kurtarma ifadesini bir yere yazmanızı şiddetle tavsiye ederiz. Kurtarma ifadenizi kendinize e-posta yoluyla göndermeyin veya ekran görüntüsü almayın. Bu ifadeyi çevrimdışı şekilde saklamak daha güvenlidir.",
- "create_wallet_continue_button" : "Devam et",
- "create_wallet_generated" : "Cüzdanınız oluşturuldu!",
- "create_wallet_generating" : "Cüzdan oluşturuluyor...",
- "create_wallet_title" : "Bir kalem ve bir kağıt alın",
- "decryption_error" : "Şifre çözme hatası",
- "deploy_contract_button" : "Onaylayın ve dağıtımını gerçekleştirin",
- "deploy_contract_title" : "Sözleşmenin dağıtımını gerçekleştirin",
- "disable_nft_marketplace_banner_description" : "Toplayın ve takas edin.",
- "dns_addresses" : {
- "few" : "%{count} adres",
- "many" : "%{count} adres",
- "one" : "%{count} adres",
- "other" : "%{count} adres"
+ "continue": "Devam et",
+ "copied": "Kopyalandı",
+ "copy_error_log": "Hata kaydını kopyalayın",
+ "create_pin_current_title": "Mevcut şifreyi girin",
+ "create_pin_new_title": "Yeni şifre oluşturun",
+ "create_pin_repeat_title": "Şifreyi tekrar girin",
+ "create_wallet_caption": "Cihazınızı kaybetmeniz durumunda cüzdanınıza erişmenin ve hesabınızı kurtarmanın tek yolu olduğu için kurtarma ifadesini bir yere yazmanızı şiddetle tavsiye ederiz. Kurtarma ifadenizi kendinize e-posta yoluyla göndermeyin veya ekran görüntüsü almayın. Bu ifadeyi çevrimdışı şekilde saklamak daha güvenlidir.",
+ "create_wallet_continue_button": "Devam et",
+ "create_wallet_generated": "Cüzdanınız oluşturuldu!",
+ "create_wallet_generating": "Cüzdan oluşturuluyor...",
+ "create_wallet_title": "Bir kalem ve bir kağıt alın",
+ "customize": "Özelleştir",
+ "customize_modal": {
+ "save": "Kaydet",
+ "subtitle": "Cüzdan adı ve simgesi cihazınızda yerel olarak saklanır.",
+ "title": "Cüzdanınızı özelleştirin",
+ "wallet_name": "Cüzdan adı"
},
- "dns_address_linked" : "Adres bağlandı",
- "dns_address_unlinked" : "Adresin bağlantısı kaldırıldı",
- "dns_alert_expiring_many" : {
- "few" : "%{count} adet süresi dolmak üzere olan alan adınız mevcuttur. Tümünü %{untilDate} tarihine kadar yenilemeniz gerekmektedir.",
- "many" : "%{count} adet süresi dolmak üzere olan alan adınız mevcuttur. Tümünü %{untilDate} tarihine kadar yenilemeniz gerekmektedir.",
- "one" : "%{count} adet süresi dolmak üzere olan alan adınız mevcuttur. Tümünü %{untilDate} tarihine kadar yenilemeniz gerekmektedir.",
- "other" : "%{count} adet süresi dolmak üzere olan alan adınız mevcuttur. Tümünü %{untilDate} tarihine kadar yenilemeniz gerekmektedir."
+ "decryption_error": "Şifre çözme hatası",
+ "deploy_contract_button": "Onaylayın ve dağıtımını gerçekleştirin",
+ "deploy_contract_title": "Sözleşmenin dağıtımını gerçekleştirin",
+ "disable_nft_marketplace_banner_description": "Toplayın ve takas edin.",
+ "dns_addresses": {
+ "few": "%{count} adres",
+ "many": "%{count} adres",
+ "one": "%{count} adres",
+ "other": "%{count} adres"
},
- "dns_alert_expiring_one" : "%{domain} alan adının süresi %{count} gün içinde dolacaktır. %{untilDate} tarihine kadar yenilemeniz gerekmektedir.",
- "dns_current_address" : "Mevcut adresiniz",
- "dns_expiration_date" : "Son geçerlilik tarihi",
- "dns_link_title" : "İşlemi onaylayın",
- "dns_on_sale_text" : "Alan adı şu anda pazar yerinde satışta. Transfer için önce satıştan kaldırmalısınız.",
- "dns_renew_all_until_btn" : "Tümünü %{untilDate} tarihine kadar yenileyin",
- "dns_renew_in_progress_btn" : "Alan adı yenileme işlemi devam ediyor... ",
- "dns_renew_toast_success" : "Alan adı 1 yıllığına yenilendi",
- "dns_renew_until_btn" : "%{untilDate} tarihine kadar yenileyin",
- "dns_renew_valid_caption" : {
- "one" : "%{count} gün içinde sona eriyor",
- "other" : "%{count} gün içinde sona eriyor"
+ "dns_address_linked": "Adres bağlandı",
+ "dns_address_unlinked": "Adresin bağlantısı kaldırıldı",
+ "dns_alert_expiring_many": {
+ "few": "%{count} adet süresi dolmak üzere olan alan adınız mevcuttur. Tümünü %{untilDate} tarihine kadar yenilemeniz gerekmektedir.",
+ "many": "%{count} adet süresi dolmak üzere olan alan adınız mevcuttur. Tümünü %{untilDate} tarihine kadar yenilemeniz gerekmektedir.",
+ "one": "%{count} adet süresi dolmak üzere olan alan adınız mevcuttur. Tümünü %{untilDate} tarihine kadar yenilemeniz gerekmektedir.",
+ "other": "%{count} adet süresi dolmak üzere olan alan adınız mevcuttur. Tümünü %{untilDate} tarihine kadar yenilemeniz gerekmektedir."
},
- "dns_replace_button" : "Değiştirin",
- "dns_replace_description" : "{{domain}} alan adının bağlanacağı cüzdan adresini ekleyin.",
- "dns_replace_save" : "Kaydet",
- "dns_unlink_title" : "Bağlantıyı kaldırmayı onaylayın",
- "dns_wallet_address" : "Cüzdan adresi",
- "domains_renewed" : "Yenilenen alan adları",
- "edit_coins_add" : "Ekle",
- "edit_coins_added" : "Eklendi",
- "edit_coins_added_toast" : "Eklendi",
- "edit_coins_hide" : "Gizle",
- "edit_coins_title" : "Kripto ekleyin",
- "encryptedComments" : {
- "encryptedComment" : "Şifrelenmiş yorum",
- "encryptedCommentModal" : {
- "button" : "Yorumun şifresini çöz",
- "checkboxLabel" : "Tekrar gösterme",
- "description" : "Yorum, gönderen tarafından şifrelenir ve şifresi yalnızca sizin tarafınızdan çözülebilir. Lütfen içeriğe dikkat edin ve dolandırıcılıklara karşı dikkatli olun.",
- "title" : "Şifrelenmiş yorum"
+ "dns_alert_expiring_one": "%{domain} alan adının süresi %{count} gün içinde dolacaktır. %{untilDate} tarihine kadar yenilemeniz gerekmektedir.",
+ "dns_current_address": "Mevcut adresiniz",
+ "dns_expiration_date": "Son geçerlilik tarihi",
+ "dns_link_title": "İşlemi onaylayın",
+ "dns_on_sale_text": "Alan adı şu anda pazar yerinde satışta. Transfer için önce satıştan kaldırmalısınız.",
+ "dns_renew_all_until_btn": "Tümünü %{untilDate} tarihine kadar yenileyin",
+ "dns_renew_in_progress_btn": "Alan adı yenileme işlemi devam ediyor... ",
+ "dns_renew_toast_success": "Alan adı 1 yıllığına yenilendi",
+ "dns_renew_until_btn": "%{untilDate} tarihine kadar yenileyin",
+ "dns_renew_valid_caption": {
+ "one": "%{count} gün içinde sona eriyor",
+ "other": "%{count} gün içinde sona eriyor"
+ },
+ "dns_replace_button": "Değiştirin",
+ "dns_replace_description": "{{domain}} alan adının bağlanacağı cüzdan adresini ekleyin.",
+ "dns_replace_save": "Kaydet",
+ "dns_unlink_title": "Bağlantıyı kaldırmayı onaylayın",
+ "dns_wallet_address": "Cüzdan adresi",
+ "domains_renewed": "Yenilenen alan adları",
+ "edit_coins_add": "Ekle",
+ "edit_coins_added": "Eklendi",
+ "edit_coins_added_toast": "Eklendi",
+ "edit_coins_hide": "Gizle",
+ "edit_coins_title": "Kripto ekleyin",
+ "encryptedComments": {
+ "encryptedComment": "Şifrelenmiş yorum",
+ "encryptedCommentModal": {
+ "button": "Yorumun şifresini çöz",
+ "checkboxLabel": "Tekrar gösterme",
+ "description": "Yorum, gönderen tarafından şifrelenir ve şifresi yalnızca sizin tarafınızdan çözülebilir. Lütfen içeriğe dikkat edin ve dolandırıcılıklara karşı dikkatli olun.",
+ "title": "Şifrelenmiş yorum"
},
- "show" : "Göster"
+ "show": "Göster"
+ },
+ "error_network": "Ağ hatası",
+ "error_occurred": "Bir hata oluştu",
+ "exchange_method_dont_show_again": "Tekrar gösterme",
+ "exchange_method_open_warning": "Tonkeeper tarafından işletilmeyen harici bir uygulamayı açıyorsunuz.",
+ "exchange_modal": {
+ "buy": "Satın al",
+ "hide": "Gizle",
+ "other_ways_to_buy": "Diğer satın alma seçenekleri",
+ "sell": "Sat",
+ "show_all": "Tümünü göster",
+ "title": "Satın Al veya Sat"
},
- "error_network" : "Ağ hatası",
- "error_occurred" : "Bir hata oluştu",
- "exchange_method_dont_show_again" : "Tekrar gösterme",
- "exchange_method_open_warning" : "Tonkeeper tarafından işletilmeyen harici bir uygulamayı açıyorsunuz.",
- "exchange_modal" : {
- "buy" : "Satın al",
- "hide" : "Gizle",
- "other_ways_to_buy" : "Diğer satın alma seçenekleri",
- "sell" : "Sat",
- "show_all" : "Tümünü göster",
- "title" : "Satın Al veya Sat"
+ "exchange": {
+ "not_exists": "Geçersiz takas kimliği"
},
- "exchange" : {
- "not_exists" : "Geçersiz takas kimliği"
+ "exchange_other_ways": "TON satın almak veya satmak için diğer seçenekler",
+ "exchange_telegram_bot": "TELEGRAM BOTU",
+ "exchange_title": "TON satın alın",
+ "expiring_domains": "Süresi dolan alan adları",
+ "finish_setup": {
+ "backup": "Cüzdan kurtarma ifadesini yedekleyin",
+ "done_button": "Tamamlandı",
+ "enable_notifications": "İşlem bildirimlerini etkinleştirin",
+ "header_title": "Kurulumu tamamla",
+ "use_biometry": "İşlemi onaylamak için %{name} kullanın"
},
- "exchange_other_ways" : "TON satın almak veya satmak için diğer seçenekler",
- "exchange_telegram_bot" : "TELEGRAM BOTU",
- "exchange_title" : "TON satın alın",
- "expiring_domains" : "Süresi dolan alan adları",
- "form_optional_indicator" : "İsteğe bağlı",
- "import_add_wallet" : "Cüzdan Ekle",
- "import_add_wallet_description" : "Yeni bir cüzdan oluşturun veya mevcut bir cüzdan ekleyin.",
- "import_existing_wallet" : "Mevcut Cüzdan",
- "import_existing_wallet_description" : "24 gizli kurtarma kelimesiyle cüzdanı içe aktarın",
- "import_new_wallet" : "Yeni Cüzdan",
- "import_new_wallet_description" : "Yeni cüzdan oluşturun",
- "import_signer" : "İmza Sahiplerini Eşleştir",
- "import_signer_description" : "Daha yüksek bir kontrol ve güvenlik seviyesi",
- "import_wallet_caption" : "Cüzdanınıza erişimi geri kazanmak için, cüzdanınızı oluşturduğunuz sırada size verilen 24 harften oluşan gizli kurtarma ifadesini girin.",
- "import_wallet_reset_caption" : "Cüzdanınızı oluşturduğunuz sırada size verilen 24 harften oluşan gizli kurtarma ifadesini girerek cüzdanınıza erişimi geri kazanın.",
- "import_wallet_title" : "Gizli kurtarma ifadenizi girin",
- "import_wallet_wrong_words_err" : "Gizli kurtarma ifadesi hatalı",
- "info_about_inactive_back" : "Geri",
- "info_about_inactive_desc1" : "Tonkeeper bu adresin bir cüzdan adresi mi yoksa akıllı bir sözleşme adresi mi olduğunu bilmiyor.",
- "info_about_inactive_desc2" : "Amacınız sadece cüzdana para yatırmak ise, devam edebilirsiniz.",
- "info_about_inactive_desc3_1" : "Eğer bir akıllı sözleşmeden otomatik bir işlem gerçekleştirmesini bekliyorsanız,",
- "info_about_inactive_desc3_2" : "- transfer işleminiz söz konusu adreste takılı kalabilir.",
- "info_about_inactive_desc3_bold" : "DEVAM ETMEYİN",
- "info_about_inactive_title" : "Etkin olmayan sözleşme",
- "intro_continue_btn" : "Başlayın",
- "intro_item1_caption" : "The Open Network'ün benzersiz mimarisi sayesinde, TON'daki işlemler saniyeler içinde gerçekleştirilir.",
- "intro_item1_title" : "Birinci sınıf hız",
- "intro_item2_caption" : "Tonkeeper, şifreleme anahtarlarınızı cihazınızda saklar. Tüm işlemler merkeziyetsiz protokoller aracılığıyla gerçekleştirildiğinden kripto paralarınız hiçbir zaman merkezi borsaların eline geçmez.",
- "intro_item2_title" : "Uçtan uca güvenlik",
- "intro_item3_caption" : "-",
- "intro_item3_title" : "-",
- "intro_title" : "XXXX'e hoş geldiniz",
- "jetton_id" : "Token kimliği: %{jettonAddress}",
- "jetton_id_copied" : "Token kimliği kopyalandı",
- "jetton_name" : "%{name} Token",
- "jetton_open_explorer" : "Detayları görüntüleyin",
- "jetton_price" : "Fiyat:",
- "jettons_list_title" : "Token'lar",
- "jettons_manage_tokens" : "Token'ları yönetin",
- "jettons_show_jettons" : "Cüzdandaki token'ları göster",
- "jetton_token" : "Token",
- "language" : {
- "language_alert" : {
- "cancel" : "İptal",
- "open" : "Ayarlar",
- "title" : "Uygulamanın dilini değiştirmek için cihaz Ayarları'na gidin"
+ "form_optional_indicator": "İsteğe bağlı",
+ "import_add_wallet": "Cüzdan Ekle",
+ "import_add_wallet_description": "Yeni bir cüzdan oluşturun veya mevcut bir cüzdan ekleyin.",
+ "import_existing_wallet": "Mevcut Cüzdan",
+ "import_existing_wallet_description": "24 gizli kurtarma kelimesiyle cüzdanı içe aktarın",
+ "import_new_wallet": "Yeni Cüzdan",
+ "import_new_wallet_description": "Yeni cüzdan oluşturun",
+ "import_signer": "İmza Sahiplerini Eşleştir",
+ "import_signer_description": "Daha yüksek bir kontrol ve güvenlik seviyesi",
+ "import_wallet_caption": "Cüzdanınıza erişimi geri kazanmak için, cüzdanınızı oluşturduğunuz sırada size verilen 24 harften oluşan gizli kurtarma ifadesini girin.",
+ "import_wallet_reset_caption": "Cüzdanınızı oluşturduğunuz sırada size verilen 24 harften oluşan gizli kurtarma ifadesini girerek cüzdanınıza erişimi geri kazanın.",
+ "import_wallet_title": "Gizli kurtarma ifadenizi girin",
+ "import_wallet_wrong_words_err": "Gizli kurtarma ifadesi hatalı",
+ "info_about_inactive_back": "Geri",
+ "info_about_inactive_desc1": "Tonkeeper bu adresin bir cüzdan adresi mi yoksa akıllı bir sözleşme adresi mi olduğunu bilmiyor.",
+ "info_about_inactive_desc2": "Amacınız sadece cüzdana para yatırmak ise, devam edebilirsiniz.",
+ "info_about_inactive_desc3_1": "Eğer bir akıllı sözleşmeden otomatik bir işlem gerçekleştirmesini bekliyorsanız,",
+ "info_about_inactive_desc3_2": "- transfer işleminiz söz konusu adreste takılı kalabilir.",
+ "info_about_inactive_desc3_bold": "DEVAM ETMEYİN",
+ "info_about_inactive_title": "Etkin olmayan sözleşme",
+ "intro_continue_btn": "Başlayın",
+ "intro_item1_caption": "The Open Network'ün benzersiz mimarisi sayesinde, TON'daki işlemler saniyeler içinde gerçekleştirilir.",
+ "intro_item1_title": "Birinci sınıf hız",
+ "intro_item2_caption": "Tonkeeper, şifreleme anahtarlarınızı cihazınızda saklar. Tüm işlemler merkeziyetsiz protokoller aracılığıyla gerçekleştirildiğinden kripto paralarınız hiçbir zaman merkezi borsaların eline geçmez.",
+ "intro_item2_title": "Uçtan uca güvenlik",
+ "intro_item3_caption": "-",
+ "intro_item3_title": "-",
+ "intro_title": "XXXX'e hoş geldiniz",
+ "jetton_id": "Token kimliği: %{jettonAddress}",
+ "jetton_id_copied": "Token kimliği kopyalandı",
+ "jetton_name": "%{name} Token",
+ "jetton_open_explorer": "Detayları görüntüleyin",
+ "jetton_price": "Fiyat:",
+ "jettons_list_title": "Token'lar",
+ "jettons_manage_tokens": "Token'ları yönetin",
+ "jettons_show_jettons": "Cüzdandaki token'ları göster",
+ "jetton_token": "Token",
+ "language": {
+ "language_alert": {
+ "cancel": "İptal",
+ "open": "Ayarlar",
+ "title": "Uygulamanın dilini değiştirmek için cihaz Ayarları'na gidin"
},
- "list_item" : {
- "title" : "Dil",
- "value" : "Türkçe"
+ "list_item": {
+ "title": "Dil",
+ "value": "Türkçe"
}
},
- "later" : "Daha sonra",
- "legal_font_license" : "Montserrat yazı tipi",
- "legal_header_title" : "Hukuki açıklama",
- "legal_licenses_title" : "Lisanslar",
- "legal_privacy" : "Gizlilik politikası",
- "legal_terms" : "Kullanım şartları",
- "link_copied" : "Bağlantı kopyalandı",
- "loading" : "Yükleniyor",
- "manage_other_coins" : "Kripto paralarımı yönet",
- "migration_cancel_btn" : "Daha sonra yükselt",
- "migration_caption" : "Tonkeeper, üyelik ödemelerini destekleyen yeni bir cüzdan formatı sunuyor. Bakiyeniz yeni bir adrese transfer edilecektir. Gizli kurtarma ifadeniz aynı kalacaktır.",
- "migration_failed" : "Geçiş işlemi başarısız oldu. Bakiyeniz transfer edilemiyor.",
- "migration_fee_info" : "Ağ ücreti ≈%{tonFee} TON (%{fiatFee})",
- "migration_in_progress" : "Cüzdan v4'e geçiş devam ediyor",
- "migration_migrate_btn" : "Cüzdanı yükseltin",
- "migration_new_wallet" : "Yeni adres",
- "migration_old_wallet" : "Eski adres",
- "migration_title" : "Cüzdanınızı yükseltin",
- "nft_about_collection" : "Koleksiyon hakkında",
- "nft_about_dns" : "TON DNS, kullanıcıların kripto cüzdanlarına, akıllı sözleşmelere ve web sitelerine insan tarafından okunabilir bir isim atamasına olanak tanıyan bir hizmettir. TON DNS ile merkeziyetsiz hizmetlere erişim, İnternetteki web sitelerine erişime benzer.",
- "nft_browse_markets" : "Piyasalara göz atın",
- "nft_chain" : "Zincir",
- "nft_change_owner_title" : "Koleksiyon sahibini değiştir",
- "nft_change_theme" : "Temayı değiştir",
- "nft_collection" : "Koleksiyon",
- "nft_collection_name" : "Koleksiyon adı",
- "nft_confirm_operation" : "Onaylayın",
- "nft_contract_address" : "Sözleşme adresi",
- "nft_deploy_collection_title" : "NFT Koleksiyonu Oluşturun",
- "nft_details" : "Detaylar",
- "nft_diamonds_description" : "TON Diamonds, Tonkeeper cüzdanınızdaki temayı değiştirme gücüne sahiptir ve temanızın rengini NFT'nizin rengiyle eşleştirir.",
- "nft_features" : "Özellikler",
- "nft_fee" : "Ücret",
- "nft_fee_and_royalties" : "Ücretler ve telif hakları",
- "nft_hide_details" : "Detayları gizle",
- "nft_item_deploy_title" : "NFT'i Mint'leyin",
- "nft_item_name" : "NFT ismi",
- "nft_link_domain_button" : "Alan adını bağlayın",
- "nft_link_domain_caption" : "Alan adını bağladıktan sonra, onu transfer edebilir ve adresiniz için bir takma ad olarak kullanabilirsiniz.",
- "nft_link_domain_mismatch_warn" : "Alan adı mevcut adresinizle bağlantılı değil. Bu alan adını içeren işlemlerde dikkatli olun.",
- "nft_link_username_button" : "İsmi bağlayın",
- "nft_link_username_caption" : "İsmi bağladıktan sonra, onu transfer edebilir ve adresiniz için bir takma ad olarak kullanabilirsiniz.",
- "nft_link_username_mismatch_warn" : "İsim mevcut adresinizle bağlantılı değil. Bu ismi içeren işlemlerde dikkatli olun.",
- "nft_marketplace_address" : "Pazar yeri",
- "nft_marketplace_banner_description" : "Satın alın, satın, toplayın ve takas edin.",
- "nft_marketplace_banner_title" : "NFT tokenleriniz burada saklanacaktır",
- "nft_marketplaces" : "Keşfedin",
- "nft_marketplaces_title" : "NFT Marketleri",
- "nft_metadata" : "Metadata",
- "nft_more" : "Genişlet",
- "nft_new_owner_address" : "Yeni sahibin adresi",
- "nft_on_sale" : "Satışta",
- "nft_on_sale_text" : "NFT şu anda pazar yerinde satışta. Transfer için önce satıştan kaldırmalısınız.",
- "nft_open_in_marketplace" : "NFT Marketi'nde görüntüleyin",
- "nft_operations_expired" : "İstek zaman aşımına uğradı, lütfen tekrar deneyin",
- "nft_operation_success" : "Tamamlandı",
- "nft_owner_address" : "Sahibi",
- "nft_price" : "Fiyat",
- "nft_proceeds" : "Kazancınız",
- "nft_properties" : "Özellikler",
- "nft_royalty" : "Telif Hakkı",
- "nft_royalty_address" : "Telif hakkı adresi",
- "nft_sale_cancel_title" : "Satıştan kaldırın",
- "nft_sale_place_title" : "NFT'yi satın",
- "nft_show_details" : "Detayları göster",
- "nft_single_nft" : "Tek NFT",
- "nft_standard" : "Token Standardı",
- "nft_title" : "NFT'ler",
- "nft_token_id" : "Token Kimliği",
- "nft_transaction_head_placeholder" : "NFT",
- "nft_transfer_comment" : "Yorum",
- "nft_transfer" : {
- "confirm" : {
- "fee" : {
- "label" : "Ücret",
- "refund_label" : "İade",
- "value" : "%{value} TON"
+ "later": "Daha sonra",
+ "legal_font_license": "Montserrat yazı tipi",
+ "legal_header_title": "Hukuki açıklama",
+ "legal_licenses_title": "Lisanslar",
+ "legal_privacy": "Gizlilik politikası",
+ "legal_terms": "Kullanım şartları",
+ "link_copied": "Bağlantı kopyalandı",
+ "loading": "Yükleniyor",
+ "manage_other_coins": "Kripto paralarımı yönet",
+ "migration_cancel_btn": "Daha sonra yükselt",
+ "migration_caption": "Tonkeeper, üyelik ödemelerini destekleyen yeni bir cüzdan formatı sunuyor. Bakiyeniz yeni bir adrese transfer edilecektir. Gizli kurtarma ifadeniz aynı kalacaktır.",
+ "migration_failed": "Geçiş işlemi başarısız oldu. Bakiyeniz transfer edilemiyor.",
+ "migration_fee_info": "Ağ ücreti ≈%{tonFee} TON (%{fiatFee})",
+ "migration_in_progress": "Cüzdan v4'e geçiş devam ediyor",
+ "migration_migrate_btn": "Cüzdanı yükseltin",
+ "migration_new_wallet": "Yeni adres",
+ "migration_old_wallet": "Eski adres",
+ "migration": {
+ "subtitle": "Devam etmek için cüzdanın kilidini açın.",
+ "title": "Cüzdanınızı Tonkeeper'ın yeni sürümüne taşıyın",
+ "with_biometry": "%{type} ile devam edin",
+ "with_passcode": "Şifreyi girin"
+ },
+ "migration_title": "Cüzdanınızı yükseltin",
+ "nft_about_collection": "Koleksiyon hakkında",
+ "nft_about_dns": "TON DNS, kullanıcıların kripto cüzdanlarına, akıllı sözleşmelere ve web sitelerine insan tarafından okunabilir bir isim atamasına olanak tanıyan bir hizmettir. TON DNS ile merkeziyetsiz hizmetlere erişim, İnternetteki web sitelerine erişime benzer.",
+ "nft_browse_markets": "Piyasalara göz atın",
+ "nft_chain": "Zincir",
+ "nft_change_owner_title": "Koleksiyon sahibini değiştir",
+ "nft_change_theme": "Temayı değiştir",
+ "nft_collection": "Koleksiyon",
+ "nft_collection_name": "Koleksiyon adı",
+ "nft_confirm_operation": "Onaylayın",
+ "nft_contract_address": "Sözleşme adresi",
+ "nft_deploy_collection_title": "NFT Koleksiyonu Oluşturun",
+ "nft_details": "Detaylar",
+ "nft_diamonds_description": "TON Diamonds, Tonkeeper cüzdanınızdaki temayı değiştirme gücüne sahiptir ve temanızın rengini NFT'nizin rengiyle eşleştirir.",
+ "nft_features": "Özellikler",
+ "nft_fee": "Ücret",
+ "nft_fee_and_royalties": "Ücretler ve telif hakları",
+ "nft_hide_details": "Detayları gizle",
+ "nft_item_deploy_title": "NFT'i Mint'leyin",
+ "nft_item_name": "NFT ismi",
+ "nft_link_domain_button": "Alan adını bağlayın",
+ "nft_link_domain_caption": "Alan adını bağladıktan sonra, onu transfer edebilir ve adresiniz için bir takma ad olarak kullanabilirsiniz.",
+ "nft_link_domain_mismatch_warn": "Alan adı mevcut adresinizle bağlantılı değil. Bu alan adını içeren işlemlerde dikkatli olun.",
+ "nft_link_username_button": "İsmi bağlayın",
+ "nft_link_username_caption": "İsmi bağladıktan sonra, onu transfer edebilir ve adresiniz için bir takma ad olarak kullanabilirsiniz.",
+ "nft_link_username_mismatch_warn": "İsim mevcut adresinizle bağlantılı değil. Bu ismi içeren işlemlerde dikkatli olun.",
+ "nft_marketplace_address": "Pazar yeri",
+ "nft_marketplace_banner_description": "Satın alın, satın, toplayın ve takas edin.",
+ "nft_marketplace_banner_title": "NFT tokenleriniz burada saklanacaktır",
+ "nft_marketplaces": "Keşfedin",
+ "nft_marketplaces_title": "NFT Marketleri",
+ "nft_metadata": "Metadata",
+ "nft_more": "Genişlet",
+ "nft_new_owner_address": "Yeni sahibin adresi",
+ "nft_on_sale": "Satışta",
+ "nft_on_sale_text": "NFT şu anda pazar yerinde satışta. Transfer için önce satıştan kaldırmalısınız.",
+ "nft_open_in_marketplace": "NFT Marketi'nde görüntüleyin",
+ "nft_operations_expired": "İstek zaman aşımına uğradı, lütfen tekrar deneyin",
+ "nft_operation_success": "Tamamlandı",
+ "nft_owner_address": "Sahibi",
+ "nft_price": "Fiyat",
+ "nft_proceeds": "Kazancınız",
+ "nft_properties": "Özellikler",
+ "nft_royalty": "Telif Hakkı",
+ "nft_royalty_address": "Telif hakkı adresi",
+ "nft_sale_cancel_title": "Satıştan kaldırın",
+ "nft_sale_place_title": "NFT'yi satın",
+ "nft_show_details": "Detayları göster",
+ "nft_single_nft": "Tek NFT",
+ "nft_standard": "Token Standardı",
+ "nft_title": "NFT'ler",
+ "nft_token_id": "Token Kimliği",
+ "nft_transaction_head_placeholder": "NFT",
+ "nft_transfer_comment": "Yorum",
+ "nft_transfer": {
+ "confirm": {
+ "fee": {
+ "label": "Ücret",
+ "refund_label": "İade",
+ "value": "%{value} TON"
}
},
- "title" : "NFT Transferi"
+ "title": "NFT Transferi"
},
- "nft_transfer_description" : "NFT bu adrese gönderilecek. Başka bir kullanıcıya NFT gönderirken dikkatli olun.",
- "nft_transfer_dns" : "Transfer edin",
- "nft_transfer_nft" : "Transfer edin",
- "nft_transfer_recipient" : "Alıcı",
- "nft_transfer_title" : "NFT'i transfer edin",
- "nft_unlink_domain_button" : "{{address}} ile bağlantılı",
- "nft_unnamed_collection" : "İsimsiz koleksiyon",
- "nft_view_in_explorer" : "Explorer'da görüntüleyin",
- "nokyc" : "KYC gerekli değildir",
- "notifications" : {
- "alert" : {
- "cancel" : "İptal",
- "description" : "Bildirimdeki bağlantı adresi uygulama adresiyle eşleşmiyor.",
- "open" : "Yine de aç",
- "title" : "Harici bir bağlantıyı açmak istediğinizden emin misiniz?"
+ "nft_transfer_description": "NFT bu adrese gönderilecek. Başka bir kullanıcıya NFT gönderirken dikkatli olun.",
+ "nft_transfer_dns": "Transfer edin",
+ "nft_transfer_nft": "Transfer edin",
+ "nft_transfer_recipient": "Alıcı",
+ "nft_transfer_title": "NFT'i transfer edin",
+ "nft_unlink_domain_button": "{{address}} ile bağlantılı",
+ "nft_unnamed_collection": "İsimsiz koleksiyon",
+ "nft_view_in_explorer": "Explorer'da görüntüleyin",
+ "nokyc": "KYC gerekli değildir",
+ "notifications": {
+ "alert": {
+ "cancel": "İptal",
+ "description": "Bildirimdeki bağlantı adresi uygulama adresiyle eşleşmiyor.",
+ "open": "Yine de aç",
+ "title": "Harici bir bağlantıyı açmak istediğinizden emin misiniz?"
},
- "allow_notifications" : "Bildirimleri etkinleştirin",
- "apps" : "Uygulamalar",
- "apps_description" : "Etkinlik sekmenizdeki bağlı uygulamalardan gelen bildirimler",
- "disconnect_app" : "%{app_name} uygulamasının bağlantısını kesin",
- "disconnected_app" : "Uygulama bağlantısı kesildi",
- "earlier" : "Daha önce",
- "from_connected" : "Bağlı uygulamalardan",
- "muted" : "Bildirimler sessize alındı",
- "mute_notifications" : "Bildirimleri sessize al",
- "notifications" : "Bildirimler",
- "placeholder" : {
- "description" : "Uygulamaları ve hizmetleri Tonkeeper tarayıcısında keşfedin.",
- "title" : "Bildirimler burada gösterilecektir"
+ "allow_notifications": "Bildirimleri etkinleştirin",
+ "apps": "Uygulamalar",
+ "apps_description": "Etkinlik sekmenizdeki bağlı uygulamalardan gelen bildirimler",
+ "disconnect_app": "%{app_name} uygulamasının bağlantısını kesin",
+ "disconnected_app": "Uygulama bağlantısı kesildi",
+ "earlier": "Daha önce",
+ "from_connected": "Bağlı uygulamalardan",
+ "muted": "Bildirimler sessize alındı",
+ "mute_notifications": "Bildirimleri sessize al",
+ "notifications": "Bildirimler",
+ "placeholder": {
+ "description": "Uygulamaları ve hizmetleri Tonkeeper tarayıcısında keşfedin.",
+ "title": "Bildirimler burada gösterilecektir"
},
- "report" : "Rapor edin"
+ "report": "Rapor edin"
},
- "notifications_disabled_action" : "Ayarları Aç",
- "notifications_disabled_description" : "Telefonunuzun ayarlarında bildirimleri kapattınız. Bildirimleri etkinleştirmek için cihazınızdaki Ayarlar'a gidin.",
- "notifications_disabled_title" : "Bildirimler devre dışı bırakıldı",
- "notifications_not_supported" : "Cihazınızda bildirimler desteklenmiyor",
- "notifications_switch_title" : "Anlık bildirimler",
- "notifications_title" : "Bildirimler",
- "notification_switch_description" : "Bağlı uygulamalardan cüzdanınıza TON, token ve NFT geldiğinde bildirim alın.",
- "notify_connection_err_caption" : "%{host} yanıt vermiyor. Lütfen daha sonra tekrar deneyin.",
- "notify_connection_err_caption_few" : "%{hosts} ve %{lastHost} yanıt vermiyor. Lütfen daha sonra tekrar deneyin.",
- "notify_connection_err_title" : "Sunucuya bağlanılamadı",
- "notify_incorrect_time_err_caption" : "Cihaz ayarlarında otomatik saat ve tarih ayarını etkinleştirin. Saatin otomatik olarak ayarlanmaması, kripto transferlerini etkileyebilir.",
- "notify_incorrect_time_err_title" : "Saat ve tarih yanlış",
- "notify_no_signal_caption" : "Lütfen internet bağlantınızı kontrol edin.",
- "notify_no_signal_title" : "Sinyal yok",
- "passcode_changed" : "Şifre değiştirildi",
- "paste" : "Yapıştır",
- "pin_enter_faceid_err" : "Biyometrik doğrulama başarısız oldu",
- "pin_enter_skip_faceid_err" : "Biyometrik kimlik doğrulama gereklidir",
- "biometry" : {
- "android" : {
- "face_recognition" : "yüz tanıma",
- "face_recognition_genitive" : "yüz tanıma",
- "fingerprint" : "Parmak izi",
- "fingerprint_genitive" : "Parmak izi"
+ "notifications_disabled_action": "Ayarları Aç",
+ "notifications_disabled_description": "Telefonunuzun ayarlarında bildirimleri kapattınız. Bildirimleri etkinleştirmek için cihazınızdaki Ayarlar'a gidin.",
+ "notifications_disabled_title": "Bildirimler devre dışı bırakıldı",
+ "notifications_not_supported": "Cihazınızda bildirimler desteklenmiyor",
+ "notifications_switch_title": "Anlık bildirimler",
+ "notifications_title": "Bildirimler",
+ "notification_switch_description": "Bağlı uygulamalardan cüzdanınıza TON, token ve NFT geldiğinde bildirim alın.",
+ "notify_connection_err_caption": "%{host} yanıt vermiyor. Lütfen daha sonra tekrar deneyin.",
+ "notify_connection_err_caption_few": "%{hosts} ve %{lastHost} yanıt vermiyor. Lütfen daha sonra tekrar deneyin.",
+ "notify_connection_err_title": "Sunucuya bağlanılamadı",
+ "notify_incorrect_time_err_caption": "Cihaz ayarlarında otomatik saat ve tarih ayarını etkinleştirin. Saatin otomatik olarak ayarlanmaması, kripto transferlerini etkileyebilir.",
+ "notify_incorrect_time_err_title": "Saat ve tarih yanlış",
+ "notify_no_signal_caption": "Lütfen internet bağlantınızı kontrol edin.",
+ "notify_no_signal_title": "Sinyal yok",
+ "passcode_changed": "Şifre değiştirildi",
+ "paste": "Yapıştır",
+ "pin_enter_faceid_err": "Biyometrik doğrulama başarısız oldu",
+ "pin_enter_skip_faceid_err": "Biyometrik kimlik doğrulama gereklidir",
+ "platform": {
+ "android": {
+ "capitalized_face_recognition": "Yüz tanıma",
+ "capitalized_fingerprint": "Parmak izi",
+ "face_recognition": "yüz tanıma",
+ "face_recognition_genitive": "yüz tanıma",
+ "fingerprint": "Parmak izi",
+ "fingerprint_genitive": "Parmak izi"
},
- "ios" : {
- "face_recognition" : "Yüz kimliği",
- "face_recognition_genitive" : "Yüz kimliği",
- "fingerprint" : "Touch ID",
- "fingerprint_genitive" : "Touch ID"
+ "ios": {
+ "capitalized_face_recognition": "Yüz kimliği",
+ "capitalized_fingerprint": "Touch ID",
+ "face_recognition": "Yüz kimliği",
+ "face_recognition_genitive": "Yüz kimliği",
+ "fingerprint": "Touch ID",
+ "fingerprint_genitive": "Touch ID"
}
},
- "programmable_nfts" : {
- "alert" : {
- "cancel" : "İptal",
- "description" : "Bu harici bağlantıyı yalnızca koleksiyonu çıkartana güveniyorsanız ziyaret edin. {{uri}}",
- "open" : "Yine de aç",
- "title" : "Harici bir bağlantıyı açmak istediğinizden emin misiniz?"
+ "programmable_nfts": {
+ "alert": {
+ "cancel": "İptal",
+ "description": "Bu harici bağlantıyı yalnızca koleksiyonu çıkartana güveniyorsanız ziyaret edin. {{uri}}",
+ "open": "Yine de aç",
+ "title": "Harici bir bağlantıyı açmak istediğinizden emin misiniz?"
}
},
- "receive_address_title" : "ya da cüzdan adresini kullanın",
- "receive_copy" : "Kopyala",
- "receiveModal" : {
- "copy" : "Kopyala",
- "receive" : "Al",
- "receive_description" : "Bu adrese yalnızca %{tokenName} ve TON ağındaki token'ları gönderin, öteki türlü kripto varlıklarınızı kaybedebilirsiniz.",
- "receive_title" : "%{tokenName} Al",
- "receive_ton" : "Bu adrese yalnızca TON ağındaki TON ve token'ları gönderin, öteki türlü kripto varlıklarınızı kaybedebilirsiniz."
+ "receive_address_title": "ya da cüzdan adresini kullanın",
+ "receive_copy": "Kopyala",
+ "receiveModal": {
+ "copy": "Kopyala",
+ "receive": "Al",
+ "receive_description": "Bu adrese yalnızca %{tokenName} ve TON ağındaki token'ları gönderin, öteki türlü kripto varlıklarınızı kaybedebilirsiniz.",
+ "receive_title": "%{tokenName} Al",
+ "receive_ton": "Bu adrese yalnızca TON ağındaki TON ve token'ları gönderin, öteki türlü kripto varlıklarınızı kaybedebilirsiniz."
},
- "receive_qr_title" : "Almak için QR kodunu gösterin",
- "receive_received_title" : "%{amount} %{currency} aldınız",
- "receive_share" : "Paylaş",
- "receive_title" : "%{currency} al",
- "receive_ton_and_jettons" : "TON ve diğer token'ları cüzdana alın",
- "refresh_app" : "Yeniden Başlat",
- "region_nokyc" : "Tarafsız bölge",
- "reminder_notifications_caption" : "Cüzdanınıza TON, token ve NFT geldiğinde bildirimler alın.",
- "reminder_notifications_enable_button" : "Bildirimleri etkinleştirin",
- "reminder_notifications_later_button" : "Daha sonra",
- "reminder_notifications_title" : "Anlık bildirimler alın",
- "renew_in_progress" : "Yenileme işlemi devam ediyor...",
- "renew_progress_of" : "%{current} / %{count}",
- "require_create_wallet_modal_caption" : "Tonkeeper'ı kullanmak için bağlı bir cüzdana ihtiyacınız var. Bunun için ya yeni bir cüzdan oluşturun ya da mevcut bir cüzdanı içe aktarın.",
- "require_create_wallet_modal_create_new" : "Yeni cüzdan oluşturun",
- "require_create_wallet_modal_import" : "Mevcut cüzdanı içe aktarın",
- "require_create_wallet_modal_title" : "Haydi şimdi cüzdanınızı ayarlayalım",
- "scan_qr_open_settings" : "Ayarları Aç",
- "scan_qr_permission_error" : "QR kodlarını tarayabilmek için kameraya erişime izin verin",
- "scan_qr_title" : "QR kodunu tarayın",
- "secret_words_caption" : "Bu 24 kelimeyi aşağıda verilen sırayla not edin ve gizli, güvenli bir yerde saklayın.",
- "secret_words_title" : "Gizli kurtarma ifadeniz",
- "security_change_passcode" : "Şifreyi değiştirin",
- "security_migration_caption" : "Artık bakiyeniz ve tüm işlemleriniz bir şifre ile güvence altına alınmıştır. Biyometrik kontrol ile de işlemlerinizi hızlandırabilirsiniz.",
- "security_migration_skip_button" : "Şimdi güncelleme yapmayın",
- "security_migration_submit_button" : "Güvenlik ayarlarını güncelleyin",
- "security_migration_title" : "Cüzdan güvenliğini güncelleyin",
- "security_reset_passcode" : "Şifreyi sıfırlayın",
- "security_title" : "Güvenlik",
- "security_use_biometry_switch" : "%{biometryType} kullanın",
- "security_use_biometry_tip" : "Cüzdanınızı her zaman bir şifre ile açabilirsiniz.",
- "send_address_placeholder" : "Adres veya isim",
- "send_all_warning_title" : "Tüm bakiyenizi göndermek istediğinizden emin misiniz?",
- "send_build_tx_error" : "İşleminiz başarısız oldu",
- "send_comment_label" : "Yorum ekleyin",
- "send_fee_estimation_error" : "Ücret hesaplanamadı",
- "send_get_wallet_info_error" : "Cüzdan bilgileri alınamadı",
- "send_insufficient_funds" : "Yetersiz bakiye",
- "send_invalid_recipient_caption" : "Alan adı mevcut değil ya da cüzdan adresi ile bağlantılı değil",
- "send_invalid_recipient_title" : "Geçersiz alıcı",
- "send_lockup_warning_caption" : "Lütfen izin verilen adrese gönderdiğinizden emin olun. İşlem başarısız olsa bile işlem ücreti kesilecektir.",
- "send_lockup_warning_submit_button" : "Gönder",
- "send_lockup_warning_title" : "Tutar likit bakiyeyi aşıyor",
- "send_publish_tx_error" : "İşlem gönderimi başarısız oldu",
- "send_screen_steps" : {
- "address" : {
- "delete_alert_text" : "Favorilerinizden «%{name}» kullanıcısını kaldırmak istediğinize emin misiniz?",
- "placeholder" : "Cüzdan adresi veya alan adı",
- "recent_label" : "En son",
- "suggest_actions" : {
- "add" : "Favorilere ekleyin",
- "delete" : "Sil",
- "edit" : "Favoriyi düzenleyin",
- "hide" : "Gizle"
+ "receive_qr_title": "Almak için QR kodunu gösterin",
+ "receive_received_title": "%{amount} %{currency} aldınız",
+ "receive_share": "Paylaş",
+ "receive_title": "%{currency} al",
+ "receive_ton_and_jettons": "TON ve diğer token'ları cüzdana alın",
+ "recovery_phrase": {
+ "caption": "Bu kelimeleri numaralarıyla birlikte not edin ve güvenli bir yerde saklayın.",
+ "check_button": "Yedekleme Kontrolü",
+ "copy_button": "Kopyala",
+ "title": "Gizli kurtarma ifadesi"
+ },
+ "refresh_app": "Yeniden Başlat",
+ "region_nokyc": "Tarafsız bölge",
+ "reminder_notifications_caption": "Cüzdanınıza TON, token ve NFT geldiğinde bildirimler alın.",
+ "reminder_notifications_enable_button": "Bildirimleri etkinleştirin",
+ "reminder_notifications_later_button": "Daha sonra",
+ "reminder_notifications_title": "Anlık bildirimler alın",
+ "renew_in_progress": "Yenileme işlemi devam ediyor...",
+ "renew_progress_of": "%{current} / %{count}",
+ "require_create_wallet_modal_caption": "Tonkeeper'ı kullanmak için bağlı bir cüzdana ihtiyacınız var. Bunun için ya yeni bir cüzdan oluşturun ya da mevcut bir cüzdanı içe aktarın.",
+ "require_create_wallet_modal_create_new": "Yeni cüzdan oluşturun",
+ "require_create_wallet_modal_import": "Mevcut cüzdanı içe aktarın",
+ "require_create_wallet_modal_title": "Haydi şimdi cüzdanınızı ayarlayalım",
+ "scan_qr_open_settings": "Ayarları Aç",
+ "scan_qr_permission_error": "QR kodlarını tarayabilmek için kameraya erişime izin verin",
+ "scan_qr_title": "QR kodunu tarayın",
+ "secret_words_caption": "Bu 24 kelimeyi aşağıda verilen sırayla not edin ve gizli, güvenli bir yerde saklayın.",
+ "secret_words_title": "Gizli kurtarma ifadeniz",
+ "security_change_passcode": "Şifreyi değiştirin",
+ "security_migration_caption": "Artık bakiyeniz ve tüm işlemleriniz bir şifre ile güvence altına alınmıştır. Biyometrik kontrol ile de işlemlerinizi hızlandırabilirsiniz.",
+ "security_migration_skip_button": "Şimdi güncelleme yapmayın",
+ "security_migration_submit_button": "Güvenlik ayarlarını güncelleyin",
+ "security_migration_title": "Cüzdan güvenliğini güncelleyin",
+ "security_reset_passcode": "Şifreyi sıfırlayın",
+ "security_title": "Güvenlik",
+ "security_use_biometry_switch": "%{biometryType} kullanın",
+ "security_use_biometry_tip": "Cüzdanınızı her zaman bir şifre ile açabilirsiniz.",
+ "send_address_placeholder": "Adres veya isim",
+ "send_all_warning_title": "Tüm bakiyenizi göndermek istediğinizden emin misiniz?",
+ "send_build_tx_error": "İşleminiz başarısız oldu",
+ "send_comment_label": "Yorum ekleyin",
+ "send_fee_estimation_error": "Ücret hesaplanamadı",
+ "send_get_wallet_info_error": "Cüzdan bilgileri alınamadı",
+ "send_insufficient_funds": "Yetersiz bakiye",
+ "send_invalid_recipient_caption": "Alan adı mevcut değil ya da cüzdan adresi ile bağlantılı değil",
+ "send_invalid_recipient_title": "Geçersiz alıcı",
+ "send_lockup_warning_caption": "Lütfen izin verilen adrese gönderdiğinizden emin olun. İşlem başarısız olsa bile işlem ücreti kesilecektir.",
+ "send_lockup_warning_submit_button": "Gönder",
+ "send_lockup_warning_title": "Tutar likit bakiyeyi aşıyor",
+ "send_publish_tx_error": "İşlem gönderimi başarısız oldu",
+ "send_screen_steps": {
+ "address": {
+ "delete_alert_text": "Favorilerinizden «%{name}» kullanıcısını kaldırmak istediğinize emin misiniz?",
+ "placeholder": "Cüzdan adresi veya alan adı",
+ "recent_label": "En son",
+ "suggest_actions": {
+ "add": "Favorilere ekleyin",
+ "delete": "Sil",
+ "edit": "Favoriyi düzenleyin",
+ "hide": "Gizle"
},
- "suggests_label" : "Favoriler ve en son erişilenler",
- "title" : "Alıcı"
+ "suggests_label": "Favoriler ve en son erişilenler",
+ "title": "Alıcı"
},
- "amount" : {
- "insufficient_balance" : "Yetersiz bakiye",
- "less_than_min" : "Minimum %{minAmount} TON",
- "liquid_jetton_note" : "tsTON likidite tokeni gönderiliyor",
- "max" : "MAX",
- "recipient_label" : "Alıcı:",
- "remaining" : "Mevcut: %{amount}",
- "title" : "Tutar"
+ "amount": {
+ "insufficient_balance": "Yetersiz bakiye",
+ "less_than_min": "Minimum %{minAmount} TON",
+ "liquid_jetton_note": "tsTON likidite tokeni gönderiliyor",
+ "max": "MAX",
+ "recipient_label": "Alıcı:",
+ "remaining": "Mevcut: %{amount}",
+ "title": "Tutar"
},
- "comfirm" : {
- "action" : "%{coin} transferi",
- "comment_decrypt" : "Şifreyi çöz",
- "comment_description" : "Herkes tarafından görülebilir olacaktır.",
- "comment_description_encrypted" : "Sadece alıcı ve siz tarafından görülebilecektir.",
- "comment_encrypt" : "Yorumu şifrele",
- "comment_label" : "Yorum",
- "comment_label_encrypted" : "Şifrelenmiş yorum",
- "comment_label_required" : "Gerekli yorum",
- "comment_required_text" : "Transfer için borsanın notunu eklemelisiniz. Aksi takdirde gönderdiğiniz tutarlar kaybolacaktır.",
- "details_label" : "Detaylar",
- "details_max_balance_label" : "Maksimum %{currency} bakiye gönderiliyor",
- "title" : "İşlemi onaylayın",
- "will_be_paid_with_battery" : "Batarya ile ödenecek"
+ "comfirm": {
+ "action": "%{coin} transferi",
+ "comment_decrypt": "Şifreyi çöz",
+ "comment_description": "Herkes tarafından görülebilir olacaktır.",
+ "comment_description_encrypted": "Sadece alıcı ve siz tarafından görülebilecektir.",
+ "comment_encrypt": "Yorumu şifrele",
+ "comment_label": "Yorum",
+ "comment_label_encrypted": "Şifrelenmiş yorum",
+ "comment_label_required": "Gerekli yorum",
+ "comment_required_text": "Transfer için borsanın notunu eklemelisiniz. Aksi takdirde gönderdiğiniz tutarlar kaybolacaktır.",
+ "details_label": "Detaylar",
+ "details_max_balance_label": "Maksimum %{currency} bakiye gönderiliyor",
+ "title": "İşlemi onaylayın",
+ "will_be_paid_with_battery": "Batarya ile ödenecek"
},
- "done" : {
- "add_favorite" : "Adresi favorilere kaydet",
- "address" : "Adres: %{address}",
- "comment" : "Yorum: %{comment}",
- "description" : "İşleminiz ağa gönderildi ve birkaç saniye içinde işleme alınacak.",
- "done_label" : "Tamamlandı",
- "favorite_saved" : "Favorilere kaydedildi",
- "fee" : "Ücret: %{fee}",
- "title" : "%{currency} gönderildi!",
- "to" : "Alıcı: %{name}"
+ "done": {
+ "add_favorite": "Adresi favorilere kaydet",
+ "address": "Adres: %{address}",
+ "comment": "Yorum: %{comment}",
+ "description": "İşleminiz ağa gönderildi ve birkaç saniye içinde işleme alınacak.",
+ "done_label": "Tamamlandı",
+ "favorite_saved": "Favorilere kaydedildi",
+ "fee": "Ücret: %{fee}",
+ "title": "%{currency} gönderildi!",
+ "to": "Alıcı: %{name}"
}
},
- "send_sending_failed" : "Gönderim başarısız oldu",
- "send_sending_wrong_time_description" : "Cihaz ayarlarında otomatik saat ve tarih ayarını açın. Ardından transfer işleminizi yeniden deneyin.",
- "send_sending_wrong_time_title" : "Hata oluştu",
- "send_title" : "%{currency} gönder",
- "settings_appearance" : "Tema",
- "settings_backup_seed" : "Gizli kurtarma ifadesini göster",
- "settings_contact_support" : "Bize Ulaşın",
- "settings_delete_account" : "Hesabı sil",
- "settings_delete_alert_button" : "Hesabı ve verileri sil",
- "settings_delete_alert_caption" : "Bu işlem hesabınızı ve bu uygulamadaki tüm verilerinizi silecektir.",
- "settings_delete_alert_title" : "\uD83D\uDEA8\uD83D\uDEA8\uD83D\uDEA8%{space}Hesabınızı silmek istediğinize emin misiniz?",
- "settings_jettons_list" : "Token'lar",
- "settings_legal_documents" : "Hukuki açıklama",
- "settings_network_alert_title" : "Ağ seçin",
- "settings_news" : "Tonkeeper Haberleri",
- "settings_notifications" : "Bildirimler",
- "settings_primary_currency" : "Para birimi",
- "settings_rate" : "Tonkeeper'i değerlendirin",
- "settings_recovery_phrase" : "Gizli kurtarma ifadesi",
- "settings_reset" : "Oturumu kapat",
- "settings_reset_alert_button" : "Oturumu kapat",
- "settings_reset_alert_caption" : "Bu işlem, cüzdan anahtarlarını siler. Gizli kurtarma ifadesini yedeklediğinizden emin olun.",
- "settings_reset_alert_title": "\uD83D\uDEA7 \uD83D\uDEA8 Oturum kapatılsın mı? \uD83D\uDEA8 \uD83D\uDEA7",
- "settings_search_engine" : "Arama",
- "settings_security" : "Güvenlik",
- "settings_subscriptions" : "Üyelikler",
- "settings_support" : "Destek",
- "settings_title" : "Ayarlar",
- "settings_to_mainnet" : "Mainnet'e geçiş yapın",
- "settings_to_testnet" : "Testnet'e geçiş yapın",
- "settings_version" : "Sürüm",
- "settings_wallet_version" : "Aktif adres",
- "setup_biometry_caption" : "%{biometryType}, şifrenizi girmeden cüzdanınızı daha hızlı açmanıza olanak tanır.",
- "setup_biometry_enable_button" : "%{biometryType} özelliğini etkinleştirin",
- "setup_biometry_title" : "%{biometryType} ile hızlı oturum açma",
- "setup_notifications_caption" : "Cüzdanınıza TON, token ve NFT geldiğinde bildirimler alın.",
- "setup_notifications_enable_button" : "Bildirimleri etkinleştirin",
- "setup_notifications_title" : "Anlık bildirimler alın",
- "signer_scan_result" : "İmzalı işlemi tarayın",
- "signer_scan_tx_description" : "Lütfen Signer'ı açın ve işlemi QR koduyla tarayın",
- "skip" : "Atla",
- "spam_action" : "İstenmeyen mesaj",
- "staking" : {
- "active" : "Aktif",
- "confirm" : {
- "address" : {
- "label" : "Alıcı adresi"
+ "send_sending_failed": "Gönderim başarısız oldu",
+ "send_sending_wrong_time_description": "Cihaz ayarlarında otomatik saat ve tarih ayarını açın. Ardından transfer işleminizi yeniden deneyin.",
+ "send_sending_wrong_time_title": "Hata oluştu",
+ "send_title": "%{currency} gönder",
+ "settings_appearance": "Tema",
+ "settings_backup_seed": "Gizli kurtarma ifadesini göster",
+ "settings_contact_support": "Bize Ulaşın",
+ "settings_delete_account": "Hesabı sil",
+ "settings_jettons_list": "Token'lar",
+ "settings_legal_documents": "Hukuki açıklama",
+ "settings_network_alert_title": "Ağ seçin",
+ "settings_news": "Tonkeeper Haberleri",
+ "settings_notifications": "Bildirimler",
+ "settings_primary_currency": "Para birimi",
+ "settings_rate": "Tonkeeper'i değerlendirin",
+ "settings_recovery_phrase": "Gizli kurtarma ifadesi",
+ "settings_reset": "Oturumu kapat",
+ "settings_reset_alert_button": "Oturumu kapat",
+ "settings_reset_alert_caption": "Bu işlem, cüzdan anahtarlarını siler. Gizli kurtarma ifadesini yedeklediğinizden emin olun.",
+ "settings_reset_alert_caption_all": "Bu işlem, tüm cüzdan anahtarlarını siler. Kurtarma ifadelerinizi yedeklediğinizden emin olun.",
+ "settings_reset_alert_title": "Oturum kapatılsın mı?",
+ "settings_reset_alert_title_all": "Tüm Cüzdanlardan Çıkış Yapılsın mı?",
+ "settings_search_engine": "Arama",
+ "settings_security": "Güvenlik",
+ "settings_subscriptions": "Üyelikler",
+ "settings_support": "Destek",
+ "settings_title": "Ayarlar",
+ "settings_to_mainnet": "Mainnet'e geçiş yapın",
+ "settings_to_testnet": "Testnet'e geçiş yapın",
+ "settings_version": "Sürüm",
+ "settings_wallet_version": "Aktif adres",
+ "setup_biometry_caption": "%{biometryType}, şifrenizi girmeden cüzdanınızı daha hızlı açmanıza olanak tanır.",
+ "setup_biometry_enable_button": "%{biometryType} özelliğini etkinleştirin",
+ "setup_biometry_title": "%{biometryType} ile hızlı oturum açma",
+ "setup_notifications_caption": "Cüzdanınıza TON, token ve NFT geldiğinde bildirimler alın.",
+ "setup_notifications_enable_button": "Bildirimleri etkinleştirin",
+ "setup_notifications_title": "Anlık bildirimler alın",
+ "signer_scan_result": "İmzalı işlemi tarayın",
+ "signer_scan_tx_description": "Lütfen Signer'ı açın ve işlemi QR koduyla tarayın",
+ "skip": "Atla",
+ "spam_action": "İstenmeyen mesaj",
+ "staking": {
+ "active": "Aktif",
+ "confirm": {
+ "address": {
+ "label": "Alıcı adresi"
},
- "amount" : {
- "label" : "Tutar",
- "value" : "%{value} TON"
+ "amount": {
+ "label": "Tutar",
+ "value": "%{value} TON"
},
- "fee" : {
- "label" : "Ücret",
- "value" : "≈ %{value} TON"
+ "fee": {
+ "label": "Ücret",
+ "value": "≈ %{value} TON"
},
- "recipient" : {
- "label" : "Alıcı"
+ "recipient": {
+ "label": "Alıcı"
},
- "withdraw_amount" : {
- "label" : "Çekilecek tutar"
+ "withdraw_amount": {
+ "label": "Çekilecek tutar"
}
},
- "confirm_deposit" : "Onaylayın ve yatırın",
- "confirm_unstake" : "Onaylayın ve geri çekin",
- "deposit" : "Yatırma",
- "desc_large" : "TONcoin stake edenler arasına katılın ve ödüller kazanın. Staking, TON ağını korumaya yardımcı olur.",
- "details" : {
- "about_pool" : "Detaylar",
- "apy" : {
- "highest_tag" : "MAKS",
- "label" : "APY",
- "value" : "≈ %{value}%"
+ "confirm_deposit": "Onaylayın ve yatırın",
+ "confirm_unstake": "Onaylayın ve geri çekin",
+ "deposit": "Yatırma",
+ "desc_large": "TONcoin stake edenler arasına katılın ve ödüller kazanın. Staking, TON ağını korumaya yardımcı olur.",
+ "details": {
+ "about_pool": "Detaylar",
+ "apy": {
+ "highest_tag": "MAKS",
+ "label": "APY",
+ "value": "≈ %{value}%"
},
- "balance" : "Staking bakiyesi",
- "cooldown" : {
- "active" : "Aktif",
- "desc" : "Her staking döngüsünün başında çekme ve yatırma işlemlerini iyileştirmek için uygulanan iki saatlik bir süre",
- "title" : "Bekleme süresi"
+ "balance": "Staking bakiyesi",
+ "cooldown": {
+ "active": "Aktif",
+ "desc": "Her staking döngüsünün başında çekme ve yatırma işlemlerini iyileştirmek için uygulanan iki saatlik bir süre",
+ "title": "Bekleme süresi"
},
- "frequency" : {
- "label" : "Ödül sıklığı",
- "value" : "Her %{count} saatte bir"
+ "frequency": {
+ "label": "Ödül sıklığı",
+ "value": "Her %{count} saatte bir"
},
- "links_title" : "Bağlantılar",
- "liquidity_token" : {
- "label" : "%{token} likidite tokeni",
- "value" : "Daha fazla bilgi edinin"
+ "links_title": "Bağlantılar",
+ "liquidity_token": {
+ "label": "%{token} likidite tokeni",
+ "value": "Daha fazla bilgi edinin"
},
- "min_deposit" : {
- "label" : "Minimum yatırabilecek tutar",
- "value" : "%{value} TON"
+ "min_deposit": {
+ "label": "Minimum yatırabilecek tutar",
+ "value": "%{value} TON"
},
- "next_cycle" : {
- "desc" : "Tüm işlemler, döngü sona erdikten sonra geçerli olur.",
- "desc_liquid" : "Tüm çekim talepleri, döngü sona erdiğinde gerçekleştirilir.",
- "in" : ":",
- "message" : "Unstake talebi, %{value} içindeki doğrulama döngüsünün bitiminden sonra işlenecektir.",
- "reward_title" : "Sonraki ödül",
- "title" : "Sonraki döngü"
+ "next_cycle": {
+ "desc": "Tüm işlemler, döngü sona erdikten sonra geçerli olur.",
+ "desc_liquid": "Tüm çekim talepleri, döngü sona erdiğinde gerçekleştirilir.",
+ "in": ":",
+ "message": "Unstake talebi, %{value} içindeki doğrulama döngüsünün bitiminden sonra işlenecektir.",
+ "reward_title": "Sonraki ödül",
+ "title": "Sonraki döngü"
},
- "note" : "Staking, üçüncü taraflar tarafından yazılan akıllı sözleşmelere dayanmaktadır. Tonkeeper, staking deneyiminizden sorumlu değildir.",
- "pendingDeposit" : "Yatırma bekleniyor",
- "pendingWithdraw" : "Çekme bekleniyor",
- "pendingWithdrawDesc" : "döngünün sonunda",
- "pool_address" : {
- "label" : "Havuz adresi"
+ "note": "Staking, üçüncü taraflar tarafından yazılan akıllı sözleşmelere dayanmaktadır. Tonkeeper, staking deneyiminizden sorumlu değildir.",
+ "pendingDeposit": "Yatırma bekleniyor",
+ "pendingWithdraw": "Çekme bekleniyor",
+ "pendingWithdrawDesc": "döngünün sonunda",
+ "pool_address": {
+ "label": "Havuz adresi"
},
- "readyWithdraw" : "Çekim için hazır",
- "socials" : {
- "telegram" : "Topluluk",
- "twitter" : "Twitter"
+ "readyWithdraw": "Çekim için hazır",
+ "socials": {
+ "telegram": "Topluluk",
+ "twitter": "Twitter"
},
- "tap_to_collect" : "Çekmek için dokunun"
+ "tap_to_collect": "Çekmek için dokunun"
},
- "estimated_profit" : "%{amount} TON - Eğer bugün TON stake ederseniz kazanacağınız yıllık kâr",
- "estimated_profit_compare" : "Mevcut staking'inize göre yılda %{amount} TON daha kârlı",
- "get_withdrawal" : "Çekim yapın",
- "highest_apy" : "MAKS. APY",
- "jetton_note" : "TON'unuzu %{poolName} havuzuna yatırdığınızda, bu tutar karşılığında havuzdaki payınızı temsil eden miktarda %{token} adlı bir token hesabınıza yatacaktır. Havuzda kâr biriktikçe, %{token} token'ınızın temsil ettiği TON miktarı artacaktır.",
- "learn_more" : "Daha fazla bilgi edinin",
- "message" : {
- "pendingDeposit" : "%{amount} TON eklenecek",
- "pendingWithdraw" : "%{amount} TON çekilecek",
- "pendingWithdrawLiquid" : "%{amount} TON, döngünün bitiminden sonra stake edilecek",
- "readyWithdraw" : "%{amount} TON çekilmeye hazır.\nÇekmek için dokunun"
+ "estimated_profit": "%{amount} TON - Eğer bugün TON stake ederseniz kazanacağınız yıllık kâr",
+ "estimated_profit_compare": "Mevcut staking'inize göre yılda %{amount} TON daha kârlı",
+ "get_withdrawal": "Çekim yapın",
+ "highest_apy": "MAKS. APY",
+ "jetton_note": "TON'unuzu %{poolName} havuzuna yatırdığınızda, bu tutar karşılığında havuzdaki payınızı temsil eden miktarda %{token} adlı bir token hesabınıza yatacaktır. Havuzda kâr biriktikçe, %{token} token'ınızın temsil ettiği TON miktarı artacaktır.",
+ "learn_more": "Daha fazla bilgi edinin",
+ "message": {
+ "pendingDeposit": "%{amount} TON eklenecek",
+ "pendingWithdraw": "%{amount} TON çekilecek",
+ "pendingWithdrawLiquid": "%{amount} TON, döngünün bitiminden sonra stake edilecek",
+ "readyWithdraw": "%{amount} TON çekilmeye hazır.\nÇekmek için dokunun"
},
- "no_funds" : "Stake havuzundan geri alınacak herhangi bir meblağ bulunmuyor",
- "not_exists" : "Geçersiz havuz adresi",
- "other" : "Diğer",
- "rewards" : {
- "after_top_up" : "Yatırma işleminden sonra",
- "current" : "Güncel",
- "title" : "APY'niz",
- "value" : "≈ %{value} TON"
+ "no_funds": "Stake havuzundan geri alınacak herhangi bir meblağ bulunmuyor",
+ "not_exists": "Geçersiz havuz adresi",
+ "other": "Diğer",
+ "rewards": {
+ "after_top_up": "Yatırma işleminden sonra",
+ "current": "Güncel",
+ "title": "APY'niz",
+ "value": "≈ %{value} TON"
},
- "send_staked_ton" : "Stake edilmiş TON",
- "staked" : "Stake edildi",
- "staked_ton" : "Stake edilmiş TON",
- "staking_desc" : "Minimum yatırma tutarı %{minStake} TON'dur. Azami %{maxApy}% oranında getiri elde edebilirsiniz.",
- "staking_pool_desc" : "APY ≈ %{apy}%",
- "title" : "Staking",
- "title_large" : "TON Staking",
- "top_up" : "Yatırma",
- "transaction" : "İşlem",
- "warning" : {
- "about" : "%{name} hakkında",
- "beta_desc" : "Staking işleminin istikrarından ve işlem sırasındaki deneyiminizden sorumlu değiliz. Bu hizmeti, tüm riski sadece kendinize ait olduğunu unutmadan kullanınız.",
- "desc" : "Staking, üçüncü taraflar tarafından yazılan akıllı sözleşmelere dayanmaktadır. Tonkeeper olarak söz konusu üçüncü tarafların çalışmaları bakımından herhangi bir sorumluluğumuz bulunmamaktadır.",
- "title" : "Uyarı"
+ "send_staked_ton": "Stake edilmiş TON",
+ "staked": "Stake edildi",
+ "staked_ton": "Stake edilmiş TON",
+ "staking_desc": "Minimum yatırma tutarı %{minStake} TON'dur. Azami %{maxApy}% oranında getiri elde edebilirsiniz.",
+ "staking_pool_desc": "APY ≈ %{apy}%",
+ "title": "Staking",
+ "title_large": "TON Staking",
+ "top_up": "Yatırma",
+ "transaction": "İşlem",
+ "warning": {
+ "about": "%{name} hakkında",
+ "beta_desc": "Staking işleminin istikrarından ve işlem sırasındaki deneyiminizden sorumlu değiliz. Bu hizmeti, tüm riski sadece kendinize ait olduğunu unutmadan kullanınız.",
+ "desc": "Staking, üçüncü taraflar tarafından yazılan akıllı sözleşmelere dayanmaktadır. Tonkeeper olarak söz konusu üçüncü tarafların çalışmaları bakımından herhangi bir sorumluluğumuz bulunmamaktadır.",
+ "title": "Uyarı"
},
- "widget_desc" : "%{apy}% kadar APY",
- "widget_staking_options" : "Staking seçenekleri",
- "widget_title" : "TON kazanın",
- "withdraw" : "Çekme",
- "withdrawal_fee_warning" : {
- "continue" : "Yine de devam et",
- "message" : "Lütfen bakiyenizde en az {{amount}} TON bırakın.",
- "title" : "Çekim yapmak için yeterli bakiyeniz bulunmamaktadır"
+ "widget_desc": "%{apy}% kadar APY",
+ "widget_staking_options": "Staking seçenekleri",
+ "widget_title": "TON kazanın",
+ "withdraw": "Çekme",
+ "withdrawal_fee_warning": {
+ "continue": "Yine de devam et",
+ "message": "Lütfen bakiyenizde en az {{amount}} TON bırakın.",
+ "title": "Çekim yapmak için yeterli bakiyeniz bulunmamaktadır"
},
- "withdrawal_request" : "Çekme talebi"
+ "withdrawal_request": "Çekme talebi"
+ },
+ "start_screen": {
+ "caption": "Yeni bir cüzdan oluşturun veya mevcut bir cüzdan ekleyin.",
+ "create_wallet_button": "Yeni cüzdan oluşturun",
+ "import_wallet_button": "Mevcut cüzdanı içe aktarın"
},
- "subscription_back_to_merchant_button" : "Geri",
- "subscription_back_to_merchant_caption" : "Talebiniz işleniyor. Üyeliğiniz yakında aktif olacaktır.",
- "subscription_back_to_merchant_name" : "%{merchantName}'e geri dön",
- "subscription_back_to_merchant_title" : "Kanala geri dönülsün mü?",
- "subscription_cancel" : "Üyeliği iptal et",
- "subscription_cancel_alert_cancel_btn" : "Şimdi değil",
- "subscription_cancel_alert_caption" : "Şimdi iptal ederseniz, hâlâ üyeliğinize %{nextBill} tarihine kadar erişebilirsiniz",
- "subscription_cancel_alert_submit_btn" : "Evet, iptal et",
- "subscription_cancel_alert_title" : "Üyeliği iptal etmek istiyor musunuz?",
- "subscription_expiring" : "Süresi sona eriyor",
- "subscription_fee" : "Ücret",
- "subscription_next_bill" : "Sonraki fatura",
- "subscription_open_merchant" : "Telegram'da aç",
- "subscription_period" : "Aralık",
- "subscription_period_custom" : "Her %{period} ",
- "subscription_period_day" : "Günlük",
- "subscription_period_half_year" : "Altı aylık",
- "subscription_period_hour" : "Saatlik",
- "subscription_period_month" : "Aylık",
- "subscription_period_quarter" : "Üç aylık",
- "subscription_period_week" : "Haftalık",
- "subscription_period_weeks" : "Her %{count} haftada bir",
- "subscription_period_year" : "Yıllık",
- "subscription_price" : "Fiyat",
- "subscription_sent" : "İşlem gönderildi",
- "subscriptions_item_caption" : "%{price} TON, sonraki fatura %{nextBill} tarihinde düzenlenecektir",
- "subscriptions_item_caption_expired" : "%{date} tarihinde süresi dolmuş",
- "subscriptions_item_caption_expiring" : "%{price} TON, %{date} tarihinde süresi doluyor",
- "subscriptions_section_active" : "Aktif",
- "subscriptions_section_expired" : "Süresi dolmuş",
- "subscription_started" : "Üyelik başlatıldı",
- "subscriptions_title" : "Üyelikler",
- "subscription_subscribe" : "Üye ol",
- "subscription_title" : "Üyelik",
- "subscription_unsubscribe" : "Üyelikten çık",
- "success" : "Başarılı!",
- "swap_title" : "Takas",
- "tab_browser" : "Tarayıcı",
- "tab_nft" : "NFT'ler",
- "tab_settings" : "Ayarlar",
- "tab_swap" : "Takas",
- "tab_wallet" : "Cüzdan",
- "today" : "Bugün",
- "tonkeeper_pro" : "Tonkeeper Pro",
- "tonkeeper_pro_description" : "Tonkeeper Pro'nun aboneliği, kripto yönetimi için bir araç seti sunan genişletilmiş bir cüzdan özelliği ile birlikte gelir",
- "ton_login_back_to_button" : "%{name}'e geri dön",
- "ton_login_caption" : "%{name}, cüzdan adresinize erişim istiyor",
- "ton_login_connect_button" : "Cüzdanı bağlayın",
- "ton_login_notice" : "Cüzdanı bağlamadan önce servis adresini kontrol ettiğinizden emin olun.",
- "ton_login_success" : "Tamamlandı",
- "ton_login_title" : "%domain'e bağlanılsın mı?",
- "transaction_bid_collection_name" : "Koleksiyon yayıncısı",
- "transaction_bid_date" : "%{date} tarihli teklif",
- "transaction_bid_dns" : "İsim",
- "transaction_buy_date" : "%{date} tarihinde satın alındı",
- "transaction_buy_status_failed" : "Başarısız",
- "transaction_buy_status_pending" : "Beklemede",
- "transaction_buy_status_success" : "Başarılı",
- "transaction_confirmations" : "Onaylar",
- "transaction_confirm_bid" : "Teklifi onayla",
- "transaction_contract_deploy_date" : "%{date}",
- "transaction_copy_caution" : "Harici bağlantılara dikkat edin. Gizli kurtarma ifadenizi üçüncü taraflarla asla paylaşmayın - yoksa tüm bakiyenizi kaybedebilirsiniz.\n\n- - -\n\n",
- "transactionDetails" : {
- "address" : "Adres",
- "bid_collection_name" : "Koleksiyon yayıncısı",
- "bid_name" : "İsim",
- "comment" : "Yorum",
- "description" : "Açıklama",
- "operation" : "İşlem",
- "payload" : "Bloğun yararlı yükü",
- "recipient" : "Alıcı",
- "recipient_address" : "Alıcı adresi",
- "sender" : "Gönderen",
- "sender_address" : "Gönderen adresi",
- "spam" : "İstenmeyen mesaj",
- "subscription_merchant_label" : "Satıcı",
- "subscription_product_label" : "Üyelik",
- "transaction" : "İşlem",
- "unsubscription_title" : "Üyelikten çıkıldı",
- "withdraw_amount" : "Çekilecek tutar"
+ "stop_watch": "İzleme Hesabını Sil",
+ "subscription_back_to_merchant_button": "Geri",
+ "subscription_back_to_merchant_caption": "Talebiniz işleniyor. Üyeliğiniz yakında aktif olacaktır.",
+ "subscription_back_to_merchant_name": "%{merchantName}'e geri dön",
+ "subscription_back_to_merchant_title": "Kanala geri dönülsün mü?",
+ "subscription_cancel": "Üyeliği iptal et",
+ "subscription_cancel_alert_cancel_btn": "Şimdi değil",
+ "subscription_cancel_alert_caption": "Şimdi iptal ederseniz, hâlâ üyeliğinize %{nextBill} tarihine kadar erişebilirsiniz",
+ "subscription_cancel_alert_submit_btn": "Evet, iptal et",
+ "subscription_cancel_alert_title": "Üyeliği iptal etmek istiyor musunuz?",
+ "subscription_expiring": "Süresi sona eriyor",
+ "subscription_fee": "Ücret",
+ "subscription_next_bill": "Sonraki fatura",
+ "subscription_open_merchant": "Telegram'da aç",
+ "subscription_period": "Aralık",
+ "subscription_period_custom": "Her %{period} ",
+ "subscription_period_day": "Günlük",
+ "subscription_period_half_year": "Altı aylık",
+ "subscription_period_hour": "Saatlik",
+ "subscription_period_month": "Aylık",
+ "subscription_period_quarter": "Üç aylık",
+ "subscription_period_week": "Haftalık",
+ "subscription_period_weeks": "Her %{count} haftada bir",
+ "subscription_period_year": "Yıllık",
+ "subscription_price": "Fiyat",
+ "subscription_sent": "İşlem gönderildi",
+ "subscriptions_item_caption": "%{price} TON, sonraki fatura %{nextBill} tarihinde düzenlenecektir",
+ "subscriptions_item_caption_expired": "%{date} tarihinde süresi dolmuş",
+ "subscriptions_item_caption_expiring": "%{price} TON, %{date} tarihinde süresi doluyor",
+ "subscriptions_section_active": "Aktif",
+ "subscriptions_section_expired": "Süresi dolmuş",
+ "subscription_started": "Üyelik başlatıldı",
+ "subscriptions_title": "Üyelikler",
+ "subscription_subscribe": "Üye ol",
+ "subscription_title": "Üyelik",
+ "subscription_unsubscribe": "Üyelikten çık",
+ "success": "Başarılı!",
+ "swap_title": "Takas",
+ "tab_browser": "Tarayıcı",
+ "tab_nft": "NFT'ler",
+ "tab_settings": "Ayarlar",
+ "tab_swap": "Takas",
+ "tab_wallet": "Cüzdan",
+ "today": "Bugün",
+ "tonkeeper_pro": "Tonkeeper Pro",
+ "tonkeeper_pro_description": "Tonkeeper Pro'nun aboneliği, kripto yönetimi için bir araç seti sunan genişletilmiş bir cüzdan özelliği ile birlikte gelir",
+ "ton_login_back_to_button": "%{name}'e geri dön",
+ "ton_login_caption": "%{name}, cüzdan adresinize erişim istiyor",
+ "ton_login_connect_button": "Cüzdanı bağlayın",
+ "ton_login_notice": "Cüzdanı bağlamadan önce servis adresini kontrol ettiğinizden emin olun.",
+ "ton_login_success": "Tamamlandı",
+ "ton_login_title": "%{0, number}omain'e bağlanılsın mı?",
+ "transaction_bid_collection_name": "Koleksiyon yayıncısı",
+ "transaction_bid_date": "%{date} tarihli teklif",
+ "transaction_bid_dns": "İsim",
+ "transaction_buy_date": "%{date} tarihinde satın alındı",
+ "transaction_buy_status_failed": "Başarısız",
+ "transaction_buy_status_pending": "Beklemede",
+ "transaction_buy_status_success": "Başarılı",
+ "transaction_confirmations": "Onaylar",
+ "transaction_confirm_bid": "Teklifi onayla",
+ "transaction_contract_deploy_date": "%{date}",
+ "transaction_copy_caution": "Harici bağlantılara dikkat edin. Gizli kurtarma ifadenizi üçüncü taraflarla asla paylaşmayın - yoksa tüm bakiyenizi kaybedebilirsiniz.\n\n- - -\n\n",
+ "transactionDetails": {
+ "address": "Adres",
+ "bid_collection_name": "Koleksiyon yayıncısı",
+ "bid_name": "İsim",
+ "comment": "Yorum",
+ "description": "Açıklama",
+ "operation": "İşlem",
+ "payload": "Bloğun yararlı yükü",
+ "recipient": "Alıcı",
+ "recipient_address": "Alıcı adresi",
+ "sender": "Gönderen",
+ "sender_address": "Gönderen adresi",
+ "spam": "İstenmeyen mesaj",
+ "subscription_merchant_label": "Satıcı",
+ "subscription_product_label": "Üyelik",
+ "transaction": "İşlem",
+ "unsubscription_title": "Üyelikten çıkıldı",
+ "withdraw_amount": "Çekilecek tutar"
},
- "transaction_exchange_from_currency" : "Satılan",
- "transaction_fee" : "Ücret",
- "transaction_hash" : "İşlem",
- "transaction_merchant" : "Satıcı",
- "transaction_message" : "Mesaj",
- "transaction_purchase_id" : "Satın Alma Kimliği",
- "transaction_receive_date" : "%{date} tarihinde alındı",
- "transaction_recipient" : "Alıcı",
- "transaction_recipient_address" : "Alıcı adresi",
- "transaction_refund" : "İade",
- "transactions" : {
- "bid" : "Teklif ver",
- "burned" : "Yakıldı",
- "contract_deploy" : "Sözleşme Dağıtımı",
- "deposit" : "Yatırma",
- "failed" : "Başarısız",
- "nft_purchase" : "NFT Satın Alma",
- "smartcontract_exec" : "Sözleşme çağrısı yap",
- "spam" : "İstenmeyen mesaj",
- "subscription" : "Üye olundu",
- "swap" : "Takas",
- "unknown" : "Bilinmeyen",
- "unknown_description" : "Bir şeyler oldu ancak anlayamadık",
- "unsubscription" : "Üyelikten çıkıldı",
- "wallet_initialized" : "Cüzdan başlatıldı",
- "withdraw" : "Çekme",
- "withdrawal_request" : "Çekme talebi"
+ "transaction_exchange_from_currency": "Satılan",
+ "transaction_fee": "Ücret",
+ "transaction_hash": "İşlem",
+ "transaction_merchant": "Satıcı",
+ "transaction_message": "Mesaj",
+ "transaction_purchase_id": "Satın Alma Kimliği",
+ "transaction_receive_date": "%{date} tarihinde alındı",
+ "transaction_recipient": "Alıcı",
+ "transaction_recipient_address": "Alıcı adresi",
+ "transaction_refund": "İade",
+ "transactions": {
+ "bid": "Teklif ver",
+ "burned": "Yakıldı",
+ "contract_deploy": "Sözleşme Dağıtımı",
+ "deposit": "Yatırma",
+ "failed": "Başarısız",
+ "nft_purchase": "NFT Satın Alma",
+ "smartcontract_exec": "Sözleşme çağrısı yap",
+ "spam": "İstenmeyen mesaj",
+ "subscription": "Üye olundu",
+ "swap": "Takas",
+ "unknown": "Bilinmeyen",
+ "unknown_description": "Bir şeyler oldu ancak anlayamadık",
+ "unsubscription": "Üyelikten çıkıldı",
+ "wallet_initialized": "Cüzdan başlatıldı",
+ "withdraw": "Çekme",
+ "withdrawal_request": "Çekme talebi"
},
- "transaction_sender" : "Gönderen",
- "transaction_sender_address" : "Gönderen adresi",
- "transaction_send_more_button" : "Bu alıcıya daha fazla gönderin",
- "transaction_sent_date" : "%{date} tarihinde gönderildi",
- "transaction_show_subscription_button" : "Üyeliği görüntüle",
- "transaction_status" : "Durum",
- "transaction_subscription" : "Üyelik",
- "transaction_subscription_date" : "%{date} tarihinde ücret tahsil edildi",
- "transaction_transfer_name" : "Transfer adı",
- "transaction_type_bid" : "Teklif verme",
- "transaction_type_bounced" : "Geri iade edildi",
- "transaction_type_buy" : "Satın alındı",
- "transaction_type_contract_deploy" : "Sözleşme Dağıtımı",
- "transaction_type_from" : "Alındı:",
- "transaction_type_new_subscriber" : "Yeni üye",
- "transaction_type_pending" : "Beklemede",
- "transaction_type_receive" : "Alındı",
- "transaction_type_sent" : "Gönderildi",
- "transaction_type_subscriber_lost" : "Üye kaybedildi",
- "transaction_type_subscription" : "Üye olundu",
- "transaction_type_to" : "Gönderildi:",
- "transaction_type_unsubscription" : "Üyelikten çıkıldı",
- "transaction_type_wallet_initialized" : "Cüzdan başlatıldı",
- "transaction_unsubscription" : "Üyelikten çıkma",
- "transaction_unsubscription_date" : "%{date}",
- "transaction_view_in_explorer" : "Explorer'da görüntüleyin",
- "transaction_wallet_initialized_date" : "%{date}",
- "transaction_your_bid" : "Teklifiniz",
- "transfer_deeplink_address_error" : "Hatalı alıcı adresi",
- "transfer_deeplink_amount_error" : "Hatalı tutar isteği",
- "transfer_deeplink_expired_error" : "Süresi dolmuş bağlantı",
- "transfer_deeplink_nft_address_error" : "Hatalı NFT adresi",
- "transfer_deeplink_unknown_token" : "Bilinmeyen token",
- "transfer_deeplink_wrong_params" : "Yanlış parametreler",
- "transfer_from_old_wallet_btn" : "Transfer et",
- "transfer_from_old_wallet_caption" : "Tonkeeper, tüm coin'leri eski adresinizden yeni adresinize transfer edecek.",
- "transfer_from_old_wallet_in_progress" : "Transfer işlemi devam ediyor",
- "transfer_from_old_wallet_title" : "Mevcut adrese transfer et",
- "txActions" : {
- "amount" : "Tutar",
- "fee" : "Ücret",
- "refund" : "İade",
- "signRaw" : {
- "addressMismatch" : {
- "wrongVersion" : {
- "close" : "İptal",
- "description" : "İşlemi onaylamak için etkin adresinizi %{version} olarak değiştirin.",
- "switch" : "Değiştir ve devam et",
- "title" : "Cüzdanınızın başka bir adresi için işlem"
+ "transaction_sender": "Gönderen",
+ "transaction_sender_address": "Gönderen adresi",
+ "transaction_send_more_button": "Bu alıcıya daha fazla gönderin",
+ "transaction_sent_date": "%{date} tarihinde gönderildi",
+ "transaction_show_subscription_button": "Üyeliği görüntüle",
+ "transaction_status": "Durum",
+ "transaction_subscription": "Üyelik",
+ "transaction_subscription_date": "%{date} tarihinde ücret tahsil edildi",
+ "transaction_transfer_name": "Transfer adı",
+ "transaction_type_bid": "Teklif verme",
+ "transaction_type_bounced": "Geri iade edildi",
+ "transaction_type_buy": "Satın alındı",
+ "transaction_type_contract_deploy": "Sözleşme Dağıtımı",
+ "transaction_type_from": "Alındı:",
+ "transaction_type_new_subscriber": "Yeni üye",
+ "transaction_type_pending": "Beklemede",
+ "transaction_type_receive": "Alındı",
+ "transaction_type_sent": "Gönderildi",
+ "transaction_type_subscriber_lost": "Üye kaybedildi",
+ "transaction_type_subscription": "Üye olundu",
+ "transaction_type_to": "Gönderildi:",
+ "transaction_type_unsubscription": "Üyelikten çıkıldı",
+ "transaction_type_wallet_initialized": "Cüzdan başlatıldı",
+ "transaction_unsubscription": "Üyelikten çıkma",
+ "transaction_unsubscription_date": "%{date}",
+ "transaction_view_in_explorer": "Explorer'da görüntüleyin",
+ "transaction_wallet_initialized_date": "%{date}",
+ "transaction_your_bid": "Teklifiniz",
+ "transfer_deeplink_address_error": "Hatalı alıcı adresi",
+ "transfer_deeplink_amount_error": "Hatalı tutar isteği",
+ "transfer_deeplink_expired_error": "Süresi dolmuş bağlantı",
+ "transfer_deeplink_nft_address_error": "Hatalı NFT adresi",
+ "transfer_deeplink_unknown_token": "Bilinmeyen token",
+ "transfer_deeplink_wrong_params": "Yanlış parametreler",
+ "transfer_from_old_wallet_btn": "Transfer et",
+ "transfer_from_old_wallet_caption": "Tonkeeper, tüm coin'leri eski adresinizden yeni adresinize transfer edecek.",
+ "transfer_from_old_wallet_in_progress": "Transfer işlemi devam ediyor",
+ "transfer_from_old_wallet_title": "Mevcut adrese transfer et",
+ "txActions": {
+ "amount": "Tutar",
+ "fee": "Ücret",
+ "refund": "İade",
+ "signRaw": {
+ "addressMismatch": {
+ "wrongVersion": {
+ "close": "İptal",
+ "description": "İşlemi onaylamak için etkin adresinizi %{version} olarak değiştirin.",
+ "switch": "Değiştir ve devam et",
+ "title": "Cüzdanınızın başka bir adresi için işlem"
},
- "wrongWallet" : {
- "close" : "Tamam",
- "description" : "%{address} numaralı başka bir cüzdan ile giriş yapın ve tekrar deneyin.",
- "title" : "Başka bir cüzdan için işlem"
+ "wrongWallet": {
+ "close": "Tamam",
+ "description": "%{address} numaralı başka bir cüzdan ile giriş yapın ve tekrar deneyin.",
+ "title": "Başka bir cüzdan için işlem"
}
},
- "comment" : "Yorum",
- "insufficientFunds" : {
- "rechargeBattery" : "Bataryayı şarj edin",
- "rechargeWallet" : "Cüzdana yeniden bakiye yükleyin",
- "stakingDeposit" : "Katılım için minimum bakiye:\n%{amount} %{currency}\n",
- "stakingFee" : "İşlem için %{amount} TON gerekiyor. Tahminen %{fee} TON ücret kesilecek, geri kalanı iade edilecektir.",
- "title" : "Yetersiz bakiye",
- "toBePaid" : "Ödenecek tutar: %{amount} %{currency}\n",
- "withFees" : "+ blokzinciri ücretleri.\n",
- "yourBalance" : "Bakiyeniz: %{balance} %{currency}."
+ "comment": "Yorum",
+ "insufficientFunds": {
+ "rechargeBattery": "Bataryayı şarj edin",
+ "rechargeWallet": "Cüzdana yeniden bakiye yükleyin",
+ "stakingDeposit": "Katılım için minimum bakiye:\n%{amount} %{currency}\n",
+ "stakingFee": "İşlem için %{amount} TON gerekiyor. Tahminen %{fee} TON ücret kesilecek, geri kalanı iade edilecektir.",
+ "title": "Yetersiz bakiye",
+ "toBePaid": "Ödenecek tutar: %{amount} %{currency}\n",
+ "withFees": "+ blokzinciri ücretleri.\n",
+ "yourBalance": "Bakiyeniz: %{balance} %{currency}."
},
- "recipient" : "Alıcı",
- "title" : "İşlemi onaylayın",
- "totalFee" : "Toplam ücret",
- "totalRefund" : "Toplam iade tutarı",
- "types" : {
- "contractDeploy" : "Sözleşme Dağıtımı",
- "jettonTransfer" : "Token Transferi",
- "nftItemTransfer" : "NFT Transferi",
- "subscribe" : "Üyelik",
- "tonTransfer" : "TON Transferi",
- "unknownTransaction" : "Bilinmeyen işlem",
- "unSubscribe" : "Üyelikten çıkma"
+ "recipient": "Alıcı",
+ "title": "İşlemi onaylayın",
+ "totalFee": "Toplam ücret",
+ "totalRefund": "Toplam iade tutarı",
+ "types": {
+ "contractDeploy": "Sözleşme Dağıtımı",
+ "jettonTransfer": "Token Transferi",
+ "nftItemTransfer": "NFT Transferi",
+ "subscribe": "Üyelik",
+ "tonTransfer": "TON Transferi",
+ "unknownTransaction": "Bilinmeyen işlem",
+ "unSubscribe": "Üyelikten çıkma"
},
- "warning_caption" : "Tonkeeper bu işlemin sonucunu tam olarak doğrulayamaz. Alıcının güvenilir olduğundan emin olun.",
- "warning_title" : "Uyarı",
- "wrongTime" : {
- "button" : "Ayarları Aç",
- "description" : "Cihazınızın saati ağ ile senkronize edilmemiş gibi görünüyor. Cihaz ayarlarına gidin ve otomatik saat ve tarih ayarını etkinleştirin.",
- "title" : "Saatler senkronize değil"
+ "warning_caption": "Tonkeeper bu işlemin sonucunu tam olarak doğrulayamaz. Alıcının güvenilir olduğundan emin olun.",
+ "warning_title": "Uyarı",
+ "wrongTime": {
+ "button": "Ayarları Aç",
+ "description": "Cihazınızın saati ağ ile senkronize edilmemiş gibi görünüyor. Cihaz ayarlarına gidin ve otomatik saat ve tarih ayarını etkinleştirin.",
+ "title": "Saatler senkronize değil"
}
}
},
- "update" : {
- "description" : "Tonkeeper'in yeni bir sürümü mevcut. Şimdi indirebilirsiniz.",
- "download" : "İndir",
- "downloading" : "İndiriliyor... {{progress}}%",
- "mb" : "{{size}} MB",
- "remindLater" : "Daha sonra hatırlat",
- "retry" : "İndirme hatası. Yeniden denemek için dokunun.",
- "tap" : "Güncellemek için dokunun",
- "title" : "Tonkeeper'ı güncelleyin",
- "version" : "Sürüm {{version}}"
+ "update": {
+ "description": "Tonkeeper'in yeni bir sürümü mevcut. Şimdi indirebilirsiniz.",
+ "download": "İndir",
+ "downloading": "İndiriliyor... {{progress}}%",
+ "mb": "{{size}} MB",
+ "remindLater": "Daha sonra hatırlat",
+ "retry": "İndirme hatası. Yeniden denemek için dokunun.",
+ "tap": "Güncellemek için dokunun",
+ "title": "Tonkeeper'ı güncelleyin",
+ "version": "Sürüm {{version}}"
},
- "username_issued_by_telegram" : "Telegram tarafından verilmiştir",
- "username_manage_name_button" : "İsmi yönet",
- "wallet_about" : "Hakkında",
- "wallet_buy" : "Satın al",
- "wallet" : {
- "buy_btn" : "TON satın alın",
- "collectibles_tab_lable" : "Koleksiyon varlıkları",
- "edit_tokens_btn" : "Düzenle",
- "nft_tab_lable" : "Koleksiyon varlıkları",
- "old_wallets_title" : "Eski cüzdanlar",
- "old_wallet_title" : "Eski cüzdan",
- "receive_btn" : "Al",
- "screen_title" : "Cüzdan",
- "send_btn" : "Gönder",
- "swap_btn" : "Takas",
- "tonkens_tab_lable" : "Tokenlar",
- "updated_at" : "%{value} tarihinde güncellendi"
+ "username_issued_by_telegram": "Telegram tarafından verilmiştir",
+ "username_manage_name_button": "İsmi yönet",
+ "wallet_about": "Hakkında",
+ "wallet_buy": "Satın al",
+ "wallet": {
+ "buy_btn": "TON satın alın",
+ "collectibles_tab_lable": "Koleksiyon varlıkları",
+ "edit_tokens_btn": "Düzenle",
+ "nft_tab_lable": "Koleksiyon varlıkları",
+ "old_wallets_title": "Eski cüzdanlar",
+ "old_wallet_title": "Eski cüzdan",
+ "receive_btn": "Al",
+ "screen_title": "Cüzdan",
+ "send_btn": "Gönder",
+ "swap_btn": "Takas",
+ "tonkens_tab_lable": "Tokenlar",
+ "updated_at": "%{value} tarihinde güncellendi"
},
- "wallet_chat" : "Sohbet",
- "wallet_community" : "Topluluk",
- "wallet_hours_symbol" : "s",
- "wallet_old_balance" : "Eski cüzdan:",
- "wallet_receive" : "Al",
- "wallet_sell" : "Sat",
- "wallet_send" : "Gönder",
- "wallet_source_code" : "Kaynak kodu",
- "wallet_swap" : "Takas",
- "wallet_title" : "Cüzdan",
- "yesterday" : "Dün"
+ "wallet_chat": "Sohbet",
+ "wallet_community": "Topluluk",
+ "wallet_hours_symbol": "s",
+ "wallet_old_balance": "Eski cüzdan:",
+ "wallet_receive": "Al",
+ "wallets": "Cüzdanlar",
+ "wallet_sell": "Sat",
+ "wallet_send": "Gönder",
+ "wallet_source_code": "Kaynak kodu",
+ "wallet_swap": "Takas",
+ "wallet_title": "Cüzdan",
+ "watch_only": "Sadece izle",
+ "yesterday": "Dün"
}
diff --git a/packages/shared/i18n/locales/tonkeeper/zh-Hans-CN.json b/packages/shared/i18n/locales/tonkeeper/zh-Hans-CN.json
index 743b07d27..3bb256ccf 100644
--- a/packages/shared/i18n/locales/tonkeeper/zh-Hans-CN.json
+++ b/packages/shared/i18n/locales/tonkeeper/zh-Hans-CN.json
@@ -1,877 +1,990 @@
{
- "about_ton" : "TON 是 Telegram 为数十亿用户设计的完全去中心化的第一层区块链。它拥有超快的交易速度、极低的费用、易于使用的应用程序,并且非常环保。",
- "access_confirmation_logout" : "退出登录",
- "access_confirmation_reset" : "重置",
- "access_confirmation_title" : "输入密码",
- "access_confirmation_update_biometry" : "输入密码以使用生物识别身份验证数据",
- "access_denied" : "访问被禁止",
- "account_deleted" : "账户已删除",
- "activity" : {
- "buy_toncoin_btn" : "购买Toncoin",
- "empty_transaction_caption" : "进行您的第一笔交易!",
- "empty_transaction_title" : "您的活动将在此显示",
- "failed_transaction" : "失败",
- "receive_btn" : "接收",
- "received" : "已接收",
- "screen_title" : "活动",
- "sent" : "已发送"
- },
- "add_edit_favorite" : {
- "address_label" : "地址",
- "add_title" : "新的收藏",
- "delete" : "删除",
- "edit_title" : "编辑收藏",
- "name_placeholder" : "名称",
- "save" : "保存"
- },
- "add_other_coins" : "增添代币",
- "address_copied" : "地址已复制",
- "appearance_accent_name" : {
- "andromeda" : "仙女座",
- "arctic" : "北极",
- "azure" : "湛蓝",
- "coral" : "珊瑚",
- "cosmos" : "宇宙",
- "default" : "Tonkeeper",
- "flamingo" : "火烈鸟",
- "fluid" : "渐变",
- "galaxy" : "银河",
- "iris" : "鸢尾",
- "marine" : "海洋",
- "ocean" : "大海",
- "sky" : "天空"
- },
- "appearance_confirm" : "设置",
- "appearance_description" : "TON Diamonds NFT将使您的钱包更加丰富多彩和独特。",
- "appearance_title" : "主题",
- "app_name" : "Tonkeeper",
- "approval" : {
- "accept" : "接受",
- "accepted" : "已接受",
- "accepted_at_collection" : "在 %{date} 接受",
- "accepted_at_token" : "在 %{date} 接受",
- "approve_all" : "接受所有",
- "approve_collection_many" : "批准来自 \"%{collection}\" 集合的传入代币",
- "approve_collection_one" : "批准来自 \"%{collection}\" 集合的传入代币",
- "approve_many" : "批准 %{count} 传入的代币",
- "approve_token" : "批准传入的代币\"%{name}\"",
- "approve_two_collections" : "批准来自 \"%{collection1}\" 和 \"%{collection2}\" 集合的传入代币",
- "approve_two_tokens" : "批准传入的代币\"%{name1}\" 和 \"%{name2}\"",
- "blacklisted_collection" : "黑名单集合",
- "blacklisted_token" : "黑名单代币",
- "decline" : "拒绝",
- "declined" : "已拒绝",
- "declined_at_collection" : "在 %{date} 拒绝",
- "declined_at_token" : "在 %{date} 拒绝",
- "details_collection" : "集合详情",
- "details_token" : "代币详细信息",
- "id_collection" : "集合ID",
- "id_token" : "代币ID",
- "manage_tokens" : "管理代币",
- "move_to_accepted" : "移至已接受",
- "move_to_declined" : "移至已拒绝",
- "name" : "名称",
- "pending" : "待定",
- "show_all" : "显示所有",
- "single_token" : "单一代币",
- "token_copied" : "代币ID已复制",
- "token_count" : {
- "one" : "%{count} 代币",
- "other" : "%{count} 代币"
+ "about_ton": "TON 是 Telegram 为数十亿用户设计的完全去中心化的第一层区块链。它拥有超快的交易速度、极低的费用、易于使用的应用程序,并且非常环保。",
+ "access_confirmation_logout": "退出登录",
+ "access_confirmation_reset": "重置",
+ "access_confirmation_title": "输入密码",
+ "access_confirmation_update_biometry": "输入密码以使用生物识别身份验证数据",
+ "access_denied": "访问被禁止",
+ "account_deleted": "账户已删除",
+ "activity": {
+ "buy_toncoin_btn": "购买Toncoin",
+ "empty_transaction_caption": "进行您的第一笔交易!",
+ "empty_transaction_title": "您的活动将在此显示",
+ "failed_transaction": "失败",
+ "receive_btn": "接收",
+ "received": "已接收",
+ "screen_title": "活动",
+ "sent": "已发送"
+ },
+ "add_edit_favorite": {
+ "address_label": "地址",
+ "add_title": "新的收藏",
+ "delete": "删除",
+ "edit_title": "编辑收藏",
+ "name_placeholder": "名称",
+ "save": "保存"
+ },
+ "add_other_coins": "增添代币",
+ "address_copied": "地址已复制",
+ "add_wallet": "添加钱包",
+ "add_wallet_modal": {
+ "create": {
+ "subtitle": "创建新钱包",
+ "title": "新钱包"
},
- "verify_collection" : "验证集合",
- "verify_description_collection" : "这些代币来自未知发行者。要检测伪造品,请使用发行者的官方来源验证集合ID。您稍后可以在设置中更改代币的可见性。",
- "verify_description_token" : "此代币来自未知发行者。要检测伪造品,请使用发行者的官方来源验证代币ID。您稍后可以在设置中更改代币的可见性。",
- "verify_token" : "验证代币",
- "whitelisted_collection" : "白名单集合",
- "whitelisted_token" : "白名单代币"
- },
- "auth_failed" : "认证失败",
- "balances_setup_wallet" : "注册钱包",
- "battery" : {
- "description" : {
- "empty" : "发送代币和 NFT,用空的主账户支付质押操作费用。"
+ "import": {
+ "subtitle": "使用24个助记词导入钱包",
+ "title": "现有钱包"
},
- "ok" : "确定",
- "packages" : {
- "buy" : "购买",
- "disclaimer" : "这是估计的转账数量。您的某些交易可能会花费更多。",
- "ok" : "确定",
- "refilled" : "电池已充电",
- "subtitle" : {
- "large" : "大杯",
- "medium" : "中杯",
- "small" : "小杯"
- }
+ "subtitle": "创建一个新钱包或添加现有钱包。",
+ "testnet": {
+ "subtitle": "使用24个助记词导入测试网钱包",
+ "title": "测试网账户"
},
- "promocode" : {
- "apply" : "应用",
- "button" : "使用优惠码充值",
- "placeholder" : "优惠码",
- "success" : "电池已充电",
- "title" : "优惠码"
+ "title": "添加钱包",
+ "watch_only": {
+ "subtitle": "在没有恢复词的情况下监控钱包活动",
+ "title": "观察账户"
+ }
+ },
+ "add_watch_only": {
+ "subtitle": "在没有恢复词的情况下监控钱包活动。您将收到来自此钱包所有交易的通知。",
+ "title": "观察账户",
+ "wallet_not_found": "钱包地址未找到"
+ },
+ "appearance_accent_name": {
+ "andromeda": "仙女座",
+ "arctic": "北极",
+ "azure": "湛蓝",
+ "coral": "珊瑚",
+ "cosmos": "宇宙",
+ "default": "Tonkeeper",
+ "flamingo": "火烈鸟",
+ "fluid": "渐变",
+ "galaxy": "银河",
+ "iris": "鸢尾",
+ "marine": "海洋",
+ "ocean": "大海",
+ "sky": "天空"
+ },
+ "appearance_confirm": "设置",
+ "appearance_description": "TON Diamonds NFT将使您的钱包更加丰富多彩和独特。",
+ "appearance_title": "主题",
+ "app_name": "Tonkeeper",
+ "approval": {
+ "accept": "接受",
+ "accepted": "已接受",
+ "accepted_at_collection": "在 %{date} 接受",
+ "accepted_at_token": "在 %{date} 接受",
+ "approve_all": "接受所有",
+ "approve_collection_many": "批准来自 \"%{collection}\" 集合的传入代币",
+ "approve_collection_one": "批准来自 \"%{collection}\" 集合的传入代币",
+ "approve_many": "批准 %{count} 传入的代币",
+ "approve_token": "批准传入的代币\"%{name}\"",
+ "approve_two_collections": "批准来自 \"%{collection1}\" 和 \"%{collection2}\" 集合的传入代币",
+ "approve_two_tokens": "批准传入的代币\"%{name1}\" 和 \"%{name2}\"",
+ "blacklisted_collection": "黑名单集合",
+ "blacklisted_token": "黑名单代币",
+ "decline": "拒绝",
+ "declined": "已拒绝",
+ "declined_at_collection": "在 %{date} 拒绝",
+ "declined_at_token": "在 %{date} 拒绝",
+ "details_collection": "集合详情",
+ "details_token": "代币详细信息",
+ "id_collection": "集合ID",
+ "id_token": "代币ID",
+ "manage_tokens": "管理代币",
+ "move_to_accepted": "移至已接受",
+ "move_to_declined": "移至已拒绝",
+ "name": "名称",
+ "pending": "待定",
+ "show_all": "显示所有",
+ "single_token": "单一代币",
+ "token_copied": "代币ID已复制",
+ "token_count": {
+ "one": "%{count} 代币",
+ "other": "%{count} 代币"
},
- "screen_title" : "电池",
- "settings" : "电池"
- },
- "browser" : {
- "about_dapps_caption" : "探索可以使用Tonkeeper进行登录和支付的应用和服务。",
- "about_dapps_learn_more" : "了解更多",
- "about_dapps_title" : "使用Tonkeeper与所有TON应用和服务",
- "actions" : {
- "copy_link" : "复制链接",
- "disconnect" : "断开连接",
- "mute" : "静音",
- "refresh" : "刷新",
- "share" : "分享"
+ "verify_collection": "验证集合",
+ "verify_description_collection": "这些代币来自未知发行者。要检测伪造品,请使用发行者的官方来源验证集合ID。您稍后可以在设置中更改代币的可见性。",
+ "verify_description_token": "此代币来自未知发行者。要检测伪造品,请使用发行者的官方来源验证代币ID。您稍后可以在设置中更改代币的可见性。",
+ "verify_token": "验证代币",
+ "whitelisted_collection": "白名单集合",
+ "whitelisted_token": "白名单代币"
+ },
+ "auth_failed": "认证失败",
+ "backup_check": {
+ "caption": "让我们看看是否全部正确。输入单词%{one},%{two}和%{three}。",
+ "done_button": "完成",
+ "title": "备份检查"
+ },
+ "backup_screen": {
+ "last_backup_time": "上次备份 %{time}",
+ "manual_backup_on": "手动备份开启",
+ "manual_button": "手动备份",
+ "manual_caption": "通过写下助记词以手动备份您的钱包。",
+ "manual_title": "手动",
+ "show_recovery_phrase": "显示恢复短语",
+ "title": "备份"
+ },
+ "backup_warning": {
+ "cancel_button": "取消",
+ "caption": "在查看您的助记词之前,请仔细阅读以下内容。",
+ "continue_button": "继续",
+ "p1": "切勿在Tonkeeper以外的任何其他地方输入您的助记词来访问您的钱包。",
+ "p2": "Tonkeeper 支持人员永远不会要求您提供助记词。",
+ "p3": "每一个知道您助记词的人都可以控制您的钱包。",
+ "title": "请注意"
+ },
+ "balances_setup_wallet": "注册钱包",
+ "battery": {
+ "description": {
+ "empty": "发送代币和 NFT,用空的主账户支付质押操作费用。",
+ "other": "您已有足够的电量以进行 %{cnt} 次交易"
},
- "connected_title" : "已连接",
- "empty_search" : "没有搜索到结果",
- "explore_all" : "探索所有",
- "more_description" : "市场、交易所等",
- "more_title" : "探索所有服务",
- "open_link" : "打开链接",
- "popular_title" : "热门",
- "remove_alert" : {
- "approve_button" : "移除",
- "title" : "移除“%{name}”?"
+ "ok": "确定",
+ "packages": {
+ "buy": "购买",
+ "disclaimer": "这是估计的转账数量。您的某些交易可能会花费更多。",
+ "ok": "确定",
+ "refilled": "电池已充电"
},
- "search_label" : "搜索或输入地址",
- "start_typing" : "输入地址或在网络上搜索",
- "title" : "浏览器",
- "web_search_title" : "%{searchEngine} 搜索"
- },
- "cancel" : "取消",
- "chart" : {
- "check_connection" : "请检查您的连接并再试一次。",
- "no_internet" : "无网络连接",
- "periods" : {
- "1D" : "天",
- "1H" : "小时",
- "1M" : "月",
- "1Y" : "年",
- "6M" : "6个月",
- "7D" : "周"
+ "promocode": {
+ "apply": "应用",
+ "button": "使用优惠码充值",
+ "placeholder": "优惠码",
+ "success": "电池已充电",
+ "title": "优惠码"
},
- "price" : "价格"
- },
- "check_words_caption" : "为了检查您是否正确地写下了您的恢复短语,请输入第%{wordNum1}、%{wordNum2}和%{wordNum3}个词。",
- "check_words_success" : "恭喜!您已经设置了您的钱包",
- "check_words_title" : "让我们检查一下",
- "choose_country" : {
- "title" : "选择您的国家"
- },
- "choose_currency" : {
- "currencies" : {
- "AED" : "阿联酋迪拉姆",
- "BDT" : "孟加拉塔卡",
- "BRL" : "巴西雷亚尔",
- "BYN" : "白俄罗斯卢布",
- "CAD" : "加拿大元",
- "CHF" : "瑞士法郎",
- "CNY" : "人民币",
- "EUR" : "欧元",
- "GBP" : "英镑",
- "GEL" : "格鲁吉亚拉里",
- "IDR" : "印尼卢比",
- "ILS" : "以色列谢克尔",
- "INR" : "印度卢比",
- "IRR" : "伊朗里亚尔",
- "JPY" : "日元",
- "KRW" : "韩元",
- "KZT" : "哈萨克斯坦坚戈",
- "NGN" : "尼日利亚奈拉",
- "RUB" : "俄罗斯卢布",
- "THB" : "泰铢",
- "TRY" : "土耳其里拉",
- "UAH" : "乌克兰格里夫纳",
- "USD" : "美元",
- "UZS" : "乌兹别克苏姆",
- "VND" : "越南盾"
+ "screen_title": "电池",
+ "settings": "电池"
+ },
+ "biometry": {
+ "android": {
+ "face_recognition": "面部识别",
+ "face_recognition_genitive": "面部识别",
+ "face_recognition_instrumental": "人脸识别",
+ "fingerprint": "指纹",
+ "fingerprint_genitive": "指纹",
+ "fingerprint_instrumental": "指纹识别"
},
- "header_title" : "主要货币"
- },
- "confirm" : "确认",
- "confirm_sending_amount" : "金额",
- "confirm_sending_fee" : "手续费",
- "confirm_sending_inactive_warn_about" : "你应该做什么",
- "confirm_sending_inactive_warn_description" : "如果您期望区块链发生奇迹,请不要继续。不会的。真的不会的。",
- "confirm_sending_inactive_warn_title" : "非活跃合约",
- "confirm_sending_message" : "Comment",
- "confirm_sending_method_title" : "将你的资金发送到%{name}?",
- "confirm_sending_recipient" : "接收者",
- "confirm_sending_recipient_address" : "接收者地址",
- "confirm_sending_sent_caption_btc" : "你的交易已经发送到网络,将在一小时内处理。",
- "confirm_sending_sent_caption_other" : "你的交易已经发送到网络,将在一分钟内处理。",
- "confirm_sending_sent_caption_ton" : "你的交易已经发送到网络,将在几秒钟内处理。",
- "confirm_sending_sent_jetton_title" : "已发送代币",
- "confirm_sending_sent_title" : "已发送币种",
- "confirm_sending_submit" : "确认并发送",
- "confirm_sending_title" : "确认发送",
- "confirmSendModal" : {
- "will_be_paid_with_battery" : "将使用电池进行支付"
- },
- "continue" : "继续",
- "copied" : "复制",
- "copy_error_log" : "复制错误指令",
- "create_pin_current_title" : "输入当前的密码",
- "create_pin_new_title" : "创建新密码",
- "create_pin_repeat_title" : "重新输入密码",
- "create_wallet_caption" : "我们强烈建议您“写下”恢复短语,因为这是访问和恢复您的钱包的唯一方式!为防失去您的设备,不要通过电子邮件发送给自己或截屏保存;也不要将其上传至在线聊天软件!离线保管更安全。",
- "create_wallet_continue_button" : "继续",
- "create_wallet_generated" : "恭喜!您的钱包已成功创建!",
- "create_wallet_generating" : "正在生成钱包...",
- "create_wallet_title" : "拿一支笔和一张纸",
- "decryption_error" : "解密错误",
- "deploy_contract_button" : "确认并部署",
- "deploy_contract_title" : "部署合同",
- "disable_nft_marketplace_banner_description" : "收集和交换。",
- "dns_address_linked" : "地址已链接",
- "dns_address_unlinked" : "地址已取消链接",
- "dns_current_address" : "您当前的地址",
- "dns_expiration_date" : "到期日期",
- "dns_link_title" : "确认交易",
- "dns_on_sale_text" : "域名现在在市场上出售。为了转移,你首先应该从销售中移除它。",
- "dns_renew_in_progress_btn" : "正在进行域名续期...",
- "dns_renew_toast_success" : "域名已续期1年",
- "dns_renew_until_btn" : "续期至 %{untilDate}",
- "dns_renew_valid_caption" : {
- "one" : "在 %{count} 天内到期",
- "other" : "在 %{count} 天内到期"
- },
- "dns_replace_button" : "替换",
- "dns_replace_description" : "添加将与{{domain}}链接的钱包地址。",
- "dns_replace_save" : "保存",
- "dns_unlink_title" : "确认取消链接",
- "dns_wallet_address" : "钱包地址",
- "edit_coins_add" : "添加",
- "edit_coins_added" : "已添加",
- "edit_coins_added_toast" : "已添加",
- "edit_coins_hide" : "隐藏",
- "edit_coins_title" : "添加加密货币",
- "error_network" : "网络错误",
- "error_occurred" : "发生了一个错误",
- "exchange_method_dont_show_again" : "不再显示",
- "exchange_method_open_warning" : "您正在打开一个非Tonkeeper操作的外部应用。",
- "exchange_modal" : {
- "hide" : "隐藏",
- "other_ways_to_buy" : "其他购买方式",
- "show_all" : "显示所有",
- "title" : "购买或出售"
- },
- "exchange_other_ways" : "其他购买或出售TON的方式",
- "exchange_telegram_bot" : "TELEGRAM机器人",
- "exchange_title" : "购买TON",
- "form_optional_indicator" : "可选",
- "import_wallet_caption" : "为了恢复到您的钱包,请输入创建钱包时给您的24个助记词。",
- "import_wallet_reset_caption" : "请恢复您的钱包\n通过输入创建钱包时写下的24个助记词。",
- "import_wallet_title" : "输入您的\n恢复短语",
- "import_wallet_wrong_words_err" : "短语不正确",
- "info_about_inactive_back" : "返回",
- "info_about_inactive_desc1" : "Tonkeeper不知道这个地址是钱包还是智能合约。",
- "info_about_inactive_desc2" : "如果你只是想存钱到一个钱包 - 你可以继续。",
- "info_about_inactive_desc3_1" : "如果你期待从一个智能合约中自动执行操作,",
- "info_about_inactive_desc3_2" : "— 你的转账可能会停在那个地址上。",
- "info_about_inactive_desc3_bold" : " !不要继续! ",
- "info_about_inactive_title" : "非活跃合约",
- "intro_continue_btn" : "开始",
- "intro_item1_caption" : "得益于 The Open Network 的独特架构,TON 交易可在数秒内完成结算。",
- "intro_item1_title" : "世界级速度",
- "intro_item2_caption" : "Tonkeeper 将您的加密密钥存储在您的设备上。所有交易都通过去中心化协议执行,因此您的加密货币绝不会落入中心化交易所的手中。",
- "intro_item2_title" : "端对端安全性能",
- "intro_item3_caption" : "-",
- "intro_item3_title" : "-",
- "intro_title" : "欢迎",
- "jetton_id" : "代币ID: %{jettonAddress}",
- "jetton_id_copied" : "代币ID已复制",
- "jetton_name" : "%{name} 代币",
- "jetton_open_explorer" : "查看详情",
- "jetton_price" : "价格:",
- "jettons_list_title" : "代币",
- "jettons_manage_tokens" : "管理代币",
- "jettons_show_jettons" : "在钱包中显示代币",
- "jetton_token" : "代币",
- "language" : {
- "list_item" : {
- "value" : "中文"
+ "default": "生物识别",
+ "default_accusative": "生物识别",
+ "default_genitive": "生物识别",
+ "default_instrumental": "生物识别",
+ "ios": {
+ "face_recognition": "Face ID",
+ "face_recognition_genitive": "Face ID",
+ "face_recognition_instrumental": "Face ID",
+ "fingerprint": "Touch ID",
+ "fingerprint_genitive": "Touch ID",
+ "fingerprint_instrumental": "Touch ID"
}
},
- "later" : "稍后",
- "legal_font_license" : "Montserrat字体",
- "legal_header_title" : "法律",
- "legal_licenses_title" : "许可证",
- "legal_privacy" : "隐私政策",
- "legal_terms" : "服务条款",
- "link_copied" : "链接已复制",
- "loading" : "加载",
- "manage_other_coins" : "管理我的代币",
- "migration_cancel_btn" : "稍后升级",
- "migration_caption" : "Tonkeeper引入了支持订阅付款的新钱包格式。您的余额将转移到新地址。您的恢复短语将保持不变。",
- "migration_failed" : "迁移失败。无法转移您的余额。",
- "migration_fee_info" : "网络费用 ≈%{tonFee} TON (%{fiatFee})",
- "migration_in_progress" : "正在进行到钱包v4的迁移",
- "migration_migrate_btn" : "升级钱包",
- "migration_new_wallet" : "新地址",
- "migration_old_wallet" : "旧地址",
- "migration_title" : "升级您的钱包",
- "nft_about_dns" : "TON DNS 是一项服务,允许用户为加密钱包、智能合约和网站分配人类可读的名称。\n\n 使用 TON DNS,像访问互联网上一样访问去中心化服务的网站。",
- "nft_browse_markets" : "浏览市场",
- "nft_chain" : "链",
- "nft_change_owner_title" : "更改集合所有者",
- "nft_change_theme" : "更改主题",
- "nft_collection" : "收藏",
- "nft_collection_name" : "集合名称",
- "nft_confirm_operation" : "确认",
- "nft_contract_address" : "合约地址",
- "nft_deploy_collection_title" : "创建NFT集合",
- "nft_details" : "详细信息",
- "nft_diamonds_description" : "TON Diamonds拥有改变你的Tonkeeper钱包主题并使其与你的NFT颜色相匹配的力量。",
- "nft_features" : "特点",
- "nft_fee" : "费用",
- "nft_fee_and_royalties" : "费用 & 版权",
- "nft_hide_details" : "隐藏详情",
- "nft_item_deploy_title" : "Mint NFT",
- "nft_item_name" : "NFT名称",
- "nft_link_domain_button" : "链接域名",
- "nft_link_domain_caption" : "链接域名后,你将能够转移它并使用它作为你的地址的别名。",
- "nft_link_domain_mismatch_warn" : "域名未链接到你当前的地址。对此域的交易要小心。",
- "nft_link_username_button" : "链接名称",
- "nft_link_username_caption" : "链接名称后,你将能够转移它并使用它作为你的地址的别名。",
- "nft_link_username_mismatch_warn" : "名称未链接到你当前的地址。对此名字的交易要小心。",
- "nft_marketplace_address" : "市场",
- "nft_marketplace_banner_description" : "购买、出售、收集和交换。",
- "nft_marketplace_banner_title" : "您的NFT代币将存储在这里",
- "nft_marketplaces" : "发现",
- "nft_marketplaces_title" : "NFT市场",
- "nft_metadata" : "元数据",
- "nft_more" : "更多",
- "nft_new_owner_address" : "新所有者地址",
- "nft_on_sale" : "正在出售",
- "nft_on_sale_text" : "NFT现在在市场上出售。为了转移,你首先应该从销售中移除它。",
- "nft_open_in_marketplace" : "在NFT市场上查看",
- "nft_operations_expired" : "请求超时,请重试",
- "nft_operation_success" : "完成",
- "nft_owner_address" : "所有者",
- "nft_price" : "价格",
- "nft_proceeds" : "您的收益",
- "nft_properties" : "属性",
- "nft_royalty" : "版税",
- "nft_royalty_address" : "版税地址",
- "nft_sale_cancel_title" : "取消出售",
- "nft_sale_place_title" : "出售NFT",
- "nft_show_details" : "显示详情",
- "nft_single_nft" : "单一NFT",
- "nft_standard" : "代币标准",
- "nft_title" : "NFTs",
- "nft_token_id" : "代币ID",
- "nft_transaction_head_placeholder" : "NFT",
- "nft_transfer_comment" : "评论",
- "nft_transfer_description" : "NFT将发送到此地址。在向其他用户发送NFT时要小心。",
- "nft_transfer_dns" : "转移",
- "nft_transfer_nft" : "转移",
- "nft_transfer_recipient" : "接收者",
- "nft_transfer_title" : "转移NFT",
- "nft_unlink_domain_button" : "已与{{address}}链接",
- "nft_unnamed_collection" : "未命名的收藏",
- "nft_view_in_explorer" : "在浏览器中查看",
- "notifications" : {
- "alert" : {
- "cancel" : "取消",
- "description" : "通知中的链接地址与应用地址不匹配。",
- "open" : "仍然打开",
- "title" : "您确定要打开外部链接吗?"
+ "browser": {
+ "about_dapps_caption": "探索可以使用Tonkeeper进行登录和支付的应用和服务。",
+ "about_dapps_learn_more": "了解更多",
+ "about_dapps_title": "使用Tonkeeper与所有TON应用和服务",
+ "actions": {
+ "copy_link": "复制链接",
+ "disconnect": "断开连接",
+ "mute": "静音",
+ "refresh": "刷新",
+ "share": "分享"
},
- "allow_notifications" : "允许通知",
- "apps" : "应用",
- "apps_description" : "在您的活动中来自已连接的应用的通知",
- "disconnect_app" : "断开%{app_name}连接",
- "disconnected_app" : "已断开应用",
- "earlier" : "早些时候",
- "from_connected" : "来自已连接的服务",
- "muted" : "已静音",
- "mute_notifications" : "静音通知",
- "notifications" : "通知",
- "placeholder" : {
- "description" : "在Tonkeeper浏览器中探索应用和服务。",
- "title" : "通知将在此处显示"
+ "connected_title": "已连接",
+ "empty_search": "没有搜索到结果",
+ "explore_all": "探索所有",
+ "more_description": "市场、交易所等",
+ "more_title": "探索所有服务",
+ "open_link": "打开链接",
+ "popular_title": "热门",
+ "remove_alert": {
+ "approve_button": "移除",
+ "title": "移除“%{name}”?"
},
- "report" : "报告"
- },
- "notifications_disabled_action" : "打开设置",
- "notifications_disabled_description" : "您在手机设置中关闭了通知。要激活通知,请转到此设备的设置。",
- "notifications_disabled_title" : "通知已禁用",
- "notifications_not_supported" : "您的设备不支持通知",
- "notifications_switch_title" : "推送通知",
- "notifications_title" : "通知",
- "notification_switch_description" : "当您收到TON、代币和NFT时获得通知。来自已连接应用的通知。",
- "notify_connection_err_caption" : "%{host} 没有响应,请稍后重试",
- "notify_connection_err_caption_few" : "%{hosts} 和 %{lastHost} 没有响应,请稍后重试",
- "notify_connection_err_title" : "连接服务器失败",
- "notify_incorrect_time_err_caption" : "请在设备设置中启用自动时间和日期。如果不自动设置时间,可能会影响资金转账。",
- "notify_incorrect_time_err_title" : "时间和日期不正确",
- "notify_no_signal_caption" : "请确认你的网络连接",
- "notify_no_signal_title" : "没有信号",
- "passcode_changed" : "密码已更改",
- "paste" : "粘贴",
- "pin_enter_faceid_err" : "生物特征检查失败",
- "pin_enter_skip_faceid_err" : "需要生物特征",
- "biometry" : {
- "android" : {
- "face_recognition" : "面部识别",
- "face_recognition_genitive" : "面部识别",
- "fingerprint" : "指纹",
- "fingerprint_genitive" : "指纹"
+ "search_label": "搜索或输入地址",
+ "start_typing": "输入地址或在网络上搜索",
+ "title": "浏览器",
+ "web_search_title": "%{searchEngine} 搜索"
+ },
+ "cancel": "取消",
+ "chart": {
+ "check_connection": "请检查您的连接并再试一次。",
+ "no_internet": "无网络连接",
+ "periods": {
+ "1D": "天",
+ "1H": "小时",
+ "1M": "月",
+ "1Y": "年",
+ "6M": "6个月",
+ "7D": "周"
},
- "ios" : {
- "face_recognition" : "Face ID",
- "face_recognition_genitive" : "Face ID",
- "fingerprint" : "Touch ID",
- "fingerprint_genitive" : "Touch ID"
+ "price": "价格"
+ },
+ "check_words_caption": "为了检查您是否正确地写下了您的恢复短语,请输入第%{wordNum1}、%{wordNum2}和%{wordNum3}个词。",
+ "check_words_success": "恭喜!您已经设置了您的钱包",
+ "check_words_title": "让我们检查一下",
+ "choose_country": {
+ "title": "选择您的国家"
+ },
+ "choose_currency": {
+ "currencies": {
+ "AED": "阿联酋迪拉姆",
+ "BDT": "孟加拉塔卡",
+ "BRL": "巴西雷亚尔",
+ "BYN": "白俄罗斯卢布",
+ "CAD": "加拿大元",
+ "CHF": "瑞士法郎",
+ "CNY": "人民币",
+ "EUR": "欧元",
+ "GBP": "英镑",
+ "GEL": "格鲁吉亚拉里",
+ "IDR": "印尼卢比",
+ "ILS": "以色列谢克尔",
+ "INR": "印度卢比",
+ "IRR": "伊朗里亚尔",
+ "JPY": "日元",
+ "KRW": "韩元",
+ "KZT": "哈萨克斯坦坚戈",
+ "NGN": "尼日利亚奈拉",
+ "RUB": "俄罗斯卢布",
+ "THB": "泰铢",
+ "TRY": "土耳其里拉",
+ "UAH": "乌克兰格里夫纳",
+ "USD": "美元",
+ "UZS": "乌兹别克苏姆",
+ "VND": "越南盾"
+ },
+ "header_title": "主要货币"
+ },
+ "choose_wallets": {
+ "subtitle": "选择您想添加的钱包。",
+ "title": "选择钱包",
+ "tokens": "代币"
+ },
+ "confirm": "确认",
+ "confirm_sending_amount": "金额",
+ "confirm_sending_fee": "手续费",
+ "confirm_sending_inactive_warn_about": "你应该做什么",
+ "confirm_sending_inactive_warn_description": "如果您期望区块链发生奇迹,请不要继续。不会的。真的不会的。",
+ "confirm_sending_inactive_warn_title": "非活跃合约",
+ "confirm_sending_message": "Comment",
+ "confirm_sending_method_title": "将你的资金发送到%{name}?",
+ "confirm_sending_recipient": "接收者",
+ "confirm_sending_recipient_address": "接收者地址",
+ "confirm_sending_sent_caption_btc": "你的交易已经发送到网络,将在一小时内处理。",
+ "confirm_sending_sent_caption_other": "你的交易已经发送到网络,将在一分钟内处理。",
+ "confirm_sending_sent_caption_ton": "你的交易已经发送到网络,将在几秒钟内处理。",
+ "confirm_sending_sent_jetton_title": "已发送代币",
+ "confirm_sending_sent_title": "已发送币种",
+ "confirm_sending_submit": "确认并发送",
+ "confirm_sending_title": "确认发送",
+ "confirmSendModal": {
+ "wallet": "钱包:",
+ "will_be_paid_with_battery": "将使用电池进行支付"
+ },
+ "continue": "继续",
+ "copied": "复制",
+ "copy_error_log": "复制错误指令",
+ "create_pin_current_title": "输入当前的密码",
+ "create_pin_new_title": "创建新密码",
+ "create_pin_repeat_title": "重新输入密码",
+ "create_wallet_caption": "我们强烈建议您“写下”恢复短语,因为这是访问和恢复您的钱包的唯一方式!为防失去您的设备,不要通过电子邮件发送给自己或截屏保存;也不要将其上传至在线聊天软件!离线保管更安全。",
+ "create_wallet_continue_button": "继续",
+ "create_wallet_generated": "恭喜!您的钱包已成功创建!",
+ "create_wallet_generating": "正在生成钱包...",
+ "create_wallet_title": "拿一支笔和一张纸",
+ "customize": "自定义",
+ "customize_modal": {
+ "save": "保存",
+ "subtitle": "钱包名称和图标将存储在您的本机设备。",
+ "title": "自定义您的钱包",
+ "wallet_name": "钱包名称"
+ },
+ "decryption_error": "解密错误",
+ "deploy_contract_button": "确认并部署",
+ "deploy_contract_title": "部署合同",
+ "disable_nft_marketplace_banner_description": "收集和交换。",
+ "dns_address_linked": "地址已链接",
+ "dns_address_unlinked": "地址已取消链接",
+ "dns_current_address": "您当前的地址",
+ "dns_expiration_date": "到期日期",
+ "dns_link_title": "确认交易",
+ "dns_on_sale_text": "域名现在在市场上出售。为了转移,你首先应该从销售中移除它。",
+ "dns_renew_in_progress_btn": "正在进行域名续期...",
+ "dns_renew_toast_success": "域名已续期1年",
+ "dns_renew_until_btn": "续期至 %{untilDate}",
+ "dns_renew_valid_caption": {
+ "one": "在 %{count} 天内到期",
+ "other": "在 %{count} 天内到期"
+ },
+ "dns_replace_button": "替换",
+ "dns_replace_description": "添加将与{{domain}}链接的钱包地址。",
+ "dns_replace_save": "保存",
+ "dns_unlink_title": "确认取消链接",
+ "dns_wallet_address": "钱包地址",
+ "edit_coins_add": "添加",
+ "edit_coins_added": "已添加",
+ "edit_coins_added_toast": "已添加",
+ "edit_coins_hide": "隐藏",
+ "edit_coins_title": "添加加密货币",
+ "error_network": "网络错误",
+ "error_occurred": "发生了一个错误",
+ "exchange_method_dont_show_again": "不再显示",
+ "exchange_method_open_warning": "您正在打开一个非Tonkeeper操作的外部应用。",
+ "exchange_modal": {
+ "hide": "隐藏",
+ "other_ways_to_buy": "其他购买方式",
+ "show_all": "显示所有",
+ "title": "购买或出售"
+ },
+ "exchange_other_ways": "其他购买或出售TON的方式",
+ "exchange_telegram_bot": "TELEGRAM机器人",
+ "exchange_title": "购买TON",
+ "finish_setup": {
+ "backup": "备份钱包助记词",
+ "done_button": "完成",
+ "enable_notifications": "启用交易通知",
+ "header_title": "完成设置",
+ "use_biometry": "使用 %{name} 批准交易"
+ },
+ "form_optional_indicator": "可选",
+ "import_add_wallet": "添加钱包",
+ "import_add_wallet_description": "创建一个新钱包或添加现有钱包。",
+ "import_existing_wallet_description": "使用24个助记词导入钱包",
+ "import_wallet_caption": "为了恢复到您的钱包,请输入创建钱包时给您的24个助记词。",
+ "import_wallet_reset_caption": "请恢复您的钱包\n通过输入创建钱包时写下的24个助记词。",
+ "import_wallet_title": "输入您的\n恢复短语",
+ "import_wallet_wrong_words_err": "短语不正确",
+ "info_about_inactive_back": "返回",
+ "info_about_inactive_desc1": "Tonkeeper不知道这个地址是钱包还是智能合约。",
+ "info_about_inactive_desc2": "如果你只是想存钱到一个钱包 - 你可以继续。",
+ "info_about_inactive_desc3_1": "如果你期待从一个智能合约中自动执行操作,",
+ "info_about_inactive_desc3_2": "— 你的转账可能会停在那个地址上。",
+ "info_about_inactive_desc3_bold": " !不要继续! ",
+ "info_about_inactive_title": "非活跃合约",
+ "intro_continue_btn": "开始",
+ "intro_item1_caption": "得益于 The Open Network 的独特架构,TON 交易可在数秒内完成结算。",
+ "intro_item1_title": "世界级速度",
+ "intro_item2_caption": "Tonkeeper 将您的加密密钥存储在您的设备上。所有交易都通过去中心化协议执行,因此您的加密货币绝不会落入中心化交易所的手中。",
+ "intro_item2_title": "端对端安全性能",
+ "intro_item3_caption": "-",
+ "intro_item3_title": "-",
+ "intro_title": "欢迎",
+ "jetton_id": "代币ID: %{jettonAddress}",
+ "jetton_id_copied": "代币ID已复制",
+ "jetton_name": "%{name} 代币",
+ "jetton_open_explorer": "查看详情",
+ "jetton_price": "价格:",
+ "jettons_list_title": "代币",
+ "jettons_manage_tokens": "管理代币",
+ "jettons_show_jettons": "在钱包中显示代币",
+ "jetton_token": "代币",
+ "language": {
+ "list_item": {
+ "value": "中文"
+ }
+ },
+ "later": "稍后",
+ "legal_font_license": "Montserrat字体",
+ "legal_header_title": "法律",
+ "legal_licenses_title": "许可证",
+ "legal_privacy": "隐私政策",
+ "legal_terms": "服务条款",
+ "link_copied": "链接已复制",
+ "loading": "加载",
+ "manage_other_coins": "管理我的代币",
+ "migration_cancel_btn": "稍后升级",
+ "migration_caption": "Tonkeeper引入了支持订阅付款的新钱包格式。您的余额将转移到新地址。您的恢复短语将保持不变。",
+ "migration_failed": "迁移失败。无法转移您的余额。",
+ "migration_fee_info": "网络费用 ≈%{tonFee} TON (%{fiatFee})",
+ "migration_in_progress": "正在进行到钱包v4的迁移",
+ "migration_migrate_btn": "升级钱包",
+ "migration_new_wallet": "新地址",
+ "migration_old_wallet": "旧地址",
+ "migration": {
+ "subtitle": "请解锁钱包以继续。",
+ "title": "将您的钱包迁移到 Tonkeeper 的新版本",
+ "with_biometry": "继续 %{type}",
+ "with_passcode": "输入密码"
+ },
+ "migration_title": "升级您的钱包",
+ "nft_about_dns": "TON DNS 是一项服务,允许用户为加密钱包、智能合约和网站分配人类可读的名称。\n\n 使用 TON DNS,像访问互联网上一样访问去中心化服务的网站。",
+ "nft_browse_markets": "浏览市场",
+ "nft_chain": "链",
+ "nft_change_owner_title": "更改集合所有者",
+ "nft_change_theme": "更改主题",
+ "nft_collection": "收藏",
+ "nft_collection_name": "集合名称",
+ "nft_confirm_operation": "确认",
+ "nft_contract_address": "合约地址",
+ "nft_deploy_collection_title": "创建NFT集合",
+ "nft_details": "详细信息",
+ "nft_diamonds_description": "TON Diamonds拥有改变你的Tonkeeper钱包主题并使其与你的NFT颜色相匹配的力量。",
+ "nft_features": "特点",
+ "nft_fee": "费用",
+ "nft_fee_and_royalties": "费用 & 版权",
+ "nft_hide_details": "隐藏详情",
+ "nft_item_deploy_title": "Mint NFT",
+ "nft_item_name": "NFT名称",
+ "nft_link_domain_button": "链接域名",
+ "nft_link_domain_caption": "链接域名后,你将能够转移它并使用它作为你的地址的别名。",
+ "nft_link_domain_mismatch_warn": "域名未链接到你当前的地址。对此域的交易要小心。",
+ "nft_link_username_button": "链接名称",
+ "nft_link_username_caption": "链接名称后,你将能够转移它并使用它作为你的地址的别名。",
+ "nft_link_username_mismatch_warn": "名称未链接到你当前的地址。对此名字的交易要小心。",
+ "nft_marketplace_address": "市场",
+ "nft_marketplace_banner_description": "购买、出售、收集和交换。",
+ "nft_marketplace_banner_title": "您的NFT代币将存储在这里",
+ "nft_marketplaces": "发现",
+ "nft_marketplaces_title": "NFT市场",
+ "nft_metadata": "元数据",
+ "nft_more": "更多",
+ "nft_new_owner_address": "新所有者地址",
+ "nft_on_sale": "正在出售",
+ "nft_on_sale_text": "NFT现在在市场上出售。为了转移,你首先应该从销售中移除它。",
+ "nft_open_in_marketplace": "在NFT市场上查看",
+ "nft_operations_expired": "请求超时,请重试",
+ "nft_operation_success": "完成",
+ "nft_owner_address": "所有者",
+ "nft_price": "价格",
+ "nft_proceeds": "您的收益",
+ "nft_properties": "属性",
+ "nft_royalty": "版税",
+ "nft_royalty_address": "版税地址",
+ "nft_sale_cancel_title": "取消出售",
+ "nft_sale_place_title": "出售NFT",
+ "nft_show_details": "显示详情",
+ "nft_single_nft": "单一NFT",
+ "nft_standard": "代币标准",
+ "nft_title": "NFTs",
+ "nft_token_id": "代币ID",
+ "nft_transaction_head_placeholder": "NFT",
+ "nft_transfer_comment": "评论",
+ "nft_transfer_description": "NFT将发送到此地址。在向其他用户发送NFT时要小心。",
+ "nft_transfer_dns": "转移",
+ "nft_transfer_nft": "转移",
+ "nft_transfer_recipient": "接收者",
+ "nft_transfer_title": "转移NFT",
+ "nft_unlink_domain_button": "已与{{address}}链接",
+ "nft_unnamed_collection": "未命名的收藏",
+ "nft_view_in_explorer": "在浏览器中查看",
+ "notifications": {
+ "alert": {
+ "cancel": "取消",
+ "description": "通知中的链接地址与应用地址不匹配。",
+ "open": "仍然打开",
+ "title": "您确定要打开外部链接吗?"
+ },
+ "allow_notifications": "允许通知",
+ "apps": "应用",
+ "apps_description": "在您的活动中来自已连接的应用的通知",
+ "disconnect_app": "断开%{app_name}连接",
+ "disconnected_app": "已断开应用",
+ "earlier": "早些时候",
+ "from_connected": "来自已连接的服务",
+ "muted": "已静音",
+ "mute_notifications": "静音通知",
+ "notifications": "通知",
+ "placeholder": {
+ "description": "在Tonkeeper浏览器中探索应用和服务。",
+ "title": "通知将在此处显示"
+ },
+ "report": "报告"
+ },
+ "notifications_disabled_action": "打开设置",
+ "notifications_disabled_description": "您在手机设置中关闭了通知。要激活通知,请转到此设备的设置。",
+ "notifications_disabled_title": "通知已禁用",
+ "notifications_not_supported": "您的设备不支持通知",
+ "notifications_switch_title": "推送通知",
+ "notifications_title": "通知",
+ "notification_switch_description": "当您收到TON、代币和NFT时获得通知。来自已连接应用的通知。",
+ "notify_connection_err_caption": "%{host} 没有响应,请稍后重试",
+ "notify_connection_err_caption_few": "%{hosts} 和 %{lastHost} 没有响应,请稍后重试",
+ "notify_connection_err_title": "连接服务器失败",
+ "notify_incorrect_time_err_caption": "请在设备设置中启用自动时间和日期。如果不自动设置时间,可能会影响资金转账。",
+ "notify_incorrect_time_err_title": "时间和日期不正确",
+ "notify_no_signal_caption": "请确认你的网络连接",
+ "notify_no_signal_title": "没有信号",
+ "passcode_changed": "密码已更改",
+ "paste": "粘贴",
+ "pin_enter_faceid_err": "生物特征检查失败",
+ "pin_enter_skip_faceid_err": "需要生物特征",
+ "platform": {
+ "android": {
+ "capitalized_face_recognition": "面部识别",
+ "capitalized_fingerprint": "指纹",
+ "face_recognition": "面部识别",
+ "face_recognition_genitive": "面部识别",
+ "fingerprint": "指纹",
+ "fingerprint_genitive": "指纹"
+ },
+ "ios": {
+ "capitalized_face_recognition": "Face ID",
+ "capitalized_fingerprint": "Touch ID",
+ "face_recognition": "Face ID",
+ "face_recognition_genitive": "Face ID",
+ "fingerprint": "Touch ID",
+ "fingerprint_genitive": "Touch ID"
}
},
- "receive_address_title" : "或使用钱包地址",
- "receive_copy" : "复制",
- "receive_qr_title" : "显示收款二维码",
- "receive_received_title" : "你已接收\n%{amount} %{currency}",
- "receive_share" : "分享",
- "receive_title" : "接收 %{currency}",
- "receive_ton_and_jettons" : "接收TON和其他代币",
- "refresh_app" : "重新刷新",
- "reminder_notifications_caption" : "当您收到TON、代币和NFT时获得通知。",
- "reminder_notifications_enable_button" : "启用通知",
- "reminder_notifications_later_button" : "稍后",
- "reminder_notifications_title" : "获得即时通知",
- "require_create_wallet_modal_caption" : "您需要一个已连接的钱包来使用\nTonkeeper。创建一个新钱包,或者导入一个现有的钱包。",
- "require_create_wallet_modal_create_new" : "创建新钱包",
- "require_create_wallet_modal_import" : "导入现有钱包",
- "require_create_wallet_modal_title" : "让我们设置您的钱包",
- "scan_qr_open_settings" : "打开设置",
- "scan_qr_permission_error" : "允许摄像头访问以扫描二维码",
- "scan_qr_title" : "扫描二维码",
- "secret_words_caption" : "按下面给出的顺序写下这24个词,并将它们存放在一个秘密的、安全的地方。",
- "secret_words_title" : "您的恢复短语",
- "security_change_passcode" : "更改密码",
- "security_migration_caption" : "现在,您的余额和任何操作都受到密码的保护。您还可以使用生物密钥来加速登入。",
- "security_migration_skip_button" : "现在不更新",
- "security_migration_submit_button" : "更新安全设置",
- "security_migration_title" : "更新钱包安全",
- "security_reset_passcode" : "重置密码",
- "security_title" : "安全",
- "security_use_biometry_switch" : "使用%{biometryType}",
- "security_use_biometry_tip" : "您始终可以使用密码解锁您的钱包。",
- "send_address_placeholder" : "地址或名称",
- "send_all_warning_title" : "你确定要发送你所有的余额吗?",
- "send_build_tx_error" : "您的交易失败",
- "send_comment_label" : "添加评论",
- "send_fee_estimation_error" : "手续费计算失败",
- "send_get_wallet_info_error" : "获取钱包信息失败",
- "send_insufficient_funds" : "资金不足",
- "send_invalid_recipient_caption" : "该域名不存在或钱包地址与其未链接",
- "send_invalid_recipient_title" : "无效接收者",
- "send_liquid_jetton_warning_title" : "你确定要发送部分质押余额吗?",
- "send_lockup_warning_caption" : "请确认你正在发送到允许的地址。\n\n即使交易失败,也会扣除手续费。",
- "send_lockup_warning_submit_button" : "发送",
- "send_lockup_warning_title" : "金额超过可用余额",
- "send_publish_tx_error" : "发送交易失败",
- "send_screen_steps" : {
- "address" : {
- "delete_alert_text" : "你确定要从收藏中删除「%{name}」吗?",
- "placeholder" : "钱包地址或域名",
- "recent_label" : "最近的",
- "suggest_actions" : {
- "add" : "添加到收藏",
- "delete" : "删除",
- "edit" : "编辑收藏",
- "hide" : "隐藏"
+ "receive_address_title": "或使用钱包地址",
+ "receive_copy": "复制",
+ "receive_qr_title": "显示收款二维码",
+ "receive_received_title": "你已接收\n%{amount} %{currency}",
+ "receive_share": "分享",
+ "receive_title": "接收 %{currency}",
+ "receive_ton_and_jettons": "接收TON和其他代币",
+ "recovery_phrase": {
+ "caption": "写下这些单词及其编号并将其存放在安全的地方。",
+ "check_button": "检查备份",
+ "copy_button": "复制",
+ "title": "助记词"
+ },
+ "refresh_app": "重新刷新",
+ "reminder_notifications_caption": "当您收到TON、代币和NFT时获得通知。",
+ "reminder_notifications_enable_button": "启用通知",
+ "reminder_notifications_later_button": "稍后",
+ "reminder_notifications_title": "获得即时通知",
+ "require_create_wallet_modal_caption": "您需要一个已连接的钱包来使用\nTonkeeper。创建一个新钱包,或者导入一个现有的钱包。",
+ "require_create_wallet_modal_create_new": "创建新钱包",
+ "require_create_wallet_modal_import": "导入现有钱包",
+ "require_create_wallet_modal_title": "让我们设置您的钱包",
+ "scan_qr_open_settings": "打开设置",
+ "scan_qr_permission_error": "允许摄像头访问以扫描二维码",
+ "scan_qr_title": "扫描二维码",
+ "secret_words_caption": "按下面给出的顺序写下这24个词,并将它们存放在一个秘密的、安全的地方。",
+ "secret_words_title": "您的恢复短语",
+ "security_change_passcode": "更改密码",
+ "security_migration_caption": "现在,您的余额和任何操作都受到密码的保护。您还可以使用生物密钥来加速登入。",
+ "security_migration_skip_button": "现在不更新",
+ "security_migration_submit_button": "更新安全设置",
+ "security_migration_title": "更新钱包安全",
+ "security_reset_passcode": "重置密码",
+ "security_title": "安全",
+ "security_use_biometry_switch": "使用%{biometryType}",
+ "security_use_biometry_tip": "您始终可以使用密码解锁您的钱包。",
+ "send_address_placeholder": "地址或名称",
+ "send_all_warning_title": "你确定要发送你所有的余额吗?",
+ "send_build_tx_error": "您的交易失败",
+ "send_comment_label": "添加评论",
+ "send_fee_estimation_error": "手续费计算失败",
+ "send_get_wallet_info_error": "获取钱包信息失败",
+ "send_insufficient_funds": "资金不足",
+ "send_invalid_recipient_caption": "该域名不存在或钱包地址与其未链接",
+ "send_invalid_recipient_title": "无效接收者",
+ "send_liquid_jetton_warning_title": "你确定要发送部分质押余额吗?",
+ "send_lockup_warning_caption": "请确认你正在发送到允许的地址。\n\n即使交易失败,也会扣除手续费。",
+ "send_lockup_warning_submit_button": "发送",
+ "send_lockup_warning_title": "金额超过可用余额",
+ "send_publish_tx_error": "发送交易失败",
+ "send_screen_steps": {
+ "address": {
+ "delete_alert_text": "你确定要从收藏中删除「%{name}」吗?",
+ "placeholder": "钱包地址或域名",
+ "recent_label": "最近的",
+ "suggest_actions": {
+ "add": "添加到收藏",
+ "delete": "删除",
+ "edit": "编辑收藏",
+ "hide": "隐藏"
},
- "suggests_label" : "收藏和最近的",
- "title" : "接收者"
+ "suggests_label": "收藏和最近的",
+ "title": "接收者"
},
- "amount" : {
- "insufficient_balance" : "余额不足",
- "less_than_min" : "最少 %{minAmount} TON",
- "max" : "最大",
- "recipient_label" : "至:",
- "remaining" : "剩余: %{amount}",
- "title" : "金额"
+ "amount": {
+ "insufficient_balance": "余额不足",
+ "less_than_min": "最少 %{minAmount} TON",
+ "max": "最大",
+ "recipient_label": "至:",
+ "remaining": "剩余: %{amount}",
+ "title": "金额"
},
- "comfirm" : {
- "action" : "%{coin} 转账",
- "comment_decrypt" : "解密",
- "comment_description" : "所有人都可以看到。",
- "comment_description_encrypted" : "只有接收者和你可以看到。",
- "comment_encrypt" : "加密 Comment",
- "comment_label" : "Comment",
- "comment_label_required" : "需要的 Comment",
- "comment_required_text" : "你必须包含交换的备注进行转账。否则你的资金将会丢失。",
- "details_label" : "详情",
- "details_max_balance_label" : "发送全部余额 %{currency}",
- "title" : "确认交易",
- "will_be_paid_with_battery" : "将使用电池进行支付"
+ "comfirm": {
+ "action": "%{coin} 转账",
+ "comment_decrypt": "解密",
+ "comment_description": "所有人都可以看到。",
+ "comment_description_encrypted": "只有接收者和你可以看到。",
+ "comment_encrypt": "加密 Comment",
+ "comment_label": "Comment",
+ "comment_label_required": "需要的 Comment",
+ "comment_required_text": "你必须包含交换的备注进行转账。否则你的资金将会丢失。",
+ "details_label": "详情",
+ "details_max_balance_label": "发送全部余额 %{currency}",
+ "title": "确认交易",
+ "will_be_paid_with_battery": "将使用电池进行支付"
},
- "done" : {
- "add_favorite" : "将地址保存到收藏",
- "address" : "地址: %{address}",
- "comment" : "评论: %{comment}",
- "description" : "你的交易已经发送到网络,将在几秒钟内处理。",
- "done_label" : "完成",
- "favorite_saved" : "保存到收藏",
- "fee" : "手续费: %{fee}",
- "title" : "%{currency} 已发送!",
- "to" : "至: %{name}"
+ "done": {
+ "add_favorite": "将地址保存到收藏",
+ "address": "地址: %{address}",
+ "comment": "评论: %{comment}",
+ "description": "你的交易已经发送到网络,将在几秒钟内处理。",
+ "done_label": "完成",
+ "favorite_saved": "保存到收藏",
+ "fee": "手续费: %{fee}",
+ "title": "%{currency} 已发送!",
+ "to": "至: %{name}"
}
},
- "send_sending_failed" : "发送失败",
- "send_sending_wrong_time_description" : "时间不同步。在设备设置中打开自动同步日期和时间后重试转账。",
- "send_sending_wrong_time_title" : "发生错误",
- "send_title" : "发送 %{currency}",
- "settings_appearance" : "主题",
- "settings_backup_seed" : "显示恢复短语",
- "settings_contact_support" : "联系我们",
- "settings_delete_account" : "删除账户",
- "settings_delete_alert_button" : "删除账户和数据",
- "settings_delete_alert_caption" : "此操作将从此应用中删除您的账户和所有数据。",
- "settings_delete_alert_title" : "\uD83D\uDEA7 \uD83D\uDEA8\uD83D\uDEA8\uD83D\uDEA8 \uD83D\uDEA7%{space}您确定要删除您的账户吗?",
- "settings_jettons_list" : "代币",
- "settings_legal_documents" : "法律文件",
- "settings_network_alert_title" : "选择网络",
- "settings_news" : "Tonkeeper新闻",
- "settings_news_url" : "https://t.me/tonkeeper",
- "settings_notifications" : "通知",
- "settings_primary_currency" : "货币",
- "settings_rate" : "为Tonkeeper评分",
- "settings_recovery_phrase" : "恢复短语",
- "settings_reset" : "退出登录",
- "settings_reset_alert_button" : "退出登录",
- "settings_reset_alert_caption" : "这将删除钱包的密钥。确保您已备份了您的秘密恢复短语。",
- "settings_reset_alert_title": "\uD83D\uDEA7 \uD83D\uDEA8 退出登录? \uD83D\uDEA8 \uD83D\uDEA7",
- "settings_search_engine" : "搜索",
- "settings_security" : "安全",
- "settings_subscriptions" : "订阅",
- "settings_support" : "支持",
- "settings_title" : "设置",
- "settings_to_mainnet" : "切换到主网",
- "settings_to_testnet" : "切换到测试网",
- "settings_version" : "版本",
- "settings_wallet_version" : "活动地址",
- "setup_biometry_caption" : "%{biometryType}允许您更快地打开您的钱包,而无需输入密码。",
- "setup_biometry_enable_button" : "启用%{biometryType}",
- "setup_biometry_title" : "使用%{biometryType}快速登录",
- "setup_notifications_caption" : "当您收到TON、代币和NFT时获得通知。",
- "setup_notifications_enable_button" : "启用通知",
- "setup_notifications_title" : "获得即时通知",
- "skip" : "跳过",
- "spam_action" : "垃圾邮件",
- "staking" : {
- "active" : "活跃的",
- "confirm" : {
- "address" : {
- "label" : "接收者地址"
+ "send_sending_failed": "发送失败",
+ "send_sending_wrong_time_description": "时间不同步。在设备设置中打开自动同步日期和时间后重试转账。",
+ "send_sending_wrong_time_title": "发生错误",
+ "send_title": "发送 %{currency}",
+ "settings_appearance": "主题",
+ "settings_backup_seed": "显示恢复短语",
+ "settings_contact_support": "联系我们",
+ "settings_delete_account": "删除账户",
+ "settings_jettons_list": "代币",
+ "settings_legal_documents": "法律文件",
+ "settings_network_alert_title": "选择网络",
+ "settings_news": "Tonkeeper新闻",
+ "settings_news_url": "https://t.me/tonkeeper",
+ "settings_notifications": "通知",
+ "settings_primary_currency": "货币",
+ "settings_rate": "为Tonkeeper评分",
+ "settings_recovery_phrase": "恢复短语",
+ "settings_reset": "退出登录",
+ "settings_reset_alert_button": "退出登录",
+ "settings_reset_alert_caption": "这将删除钱包的密钥。确保您已备份了您的秘密恢复短语。",
+ "settings_reset_alert_caption_all": "这将删除所有钱包的密钥。确保您已备份了您的助记词。",
+ "settings_reset_alert_title": "退出登录?",
+ "settings_reset_alert_title_all": "注销所有钱包?",
+ "settings_search_engine": "搜索",
+ "settings_security": "安全",
+ "settings_subscriptions": "订阅",
+ "settings_support": "支持",
+ "settings_title": "设置",
+ "settings_to_mainnet": "切换到主网",
+ "settings_to_testnet": "切换到测试网",
+ "settings_version": "版本",
+ "settings_wallet_version": "活动地址",
+ "setup_biometry_caption": "%{biometryType}允许您更快地打开您的钱包,而无需输入密码。",
+ "setup_biometry_enable_button": "启用%{biometryType}",
+ "setup_biometry_title": "使用%{biometryType}快速登录",
+ "setup_notifications_caption": "当您收到TON、代币和NFT时获得通知。",
+ "setup_notifications_enable_button": "启用通知",
+ "setup_notifications_title": "获得即时通知",
+ "skip": "跳过",
+ "spam_action": "垃圾邮件",
+ "staking": {
+ "active": "活跃的",
+ "confirm": {
+ "address": {
+ "label": "接收者地址"
},
- "amount" : {
- "label" : "金额"
+ "amount": {
+ "label": "金额"
},
- "fee" : {
- "label" : "费用",
- "value" : "≈ %{value} TON"
+ "fee": {
+ "label": "费用",
+ "value": "≈ %{value} TON"
},
- "recipient" : {
- "label" : "接收者"
+ "recipient": {
+ "label": "接收者"
},
- "withdraw_amount" : {
- "label" : "提款金额"
+ "withdraw_amount": {
+ "label": "提款金额"
}
},
- "deposit" : "存款",
- "details" : {
- "about_pool" : "关于质押池",
- "apy" : {
- "label" : "预估年化收益率",
- "value" : "≈ %{value}%"
+ "deposit": "存款",
+ "details": {
+ "about_pool": "关于质押池",
+ "apy": {
+ "label": "预估年化收益率",
+ "value": "≈ %{value}%"
},
- "balance" : "质押余额",
- "cooldown" : {
- "active" : "活跃的",
- "desc" : "应用于每个质押周期开始的两小时时段,以改善周期之间的存款和提款过程",
- "title" : "冷却时间"
+ "balance": "质押余额",
+ "cooldown": {
+ "active": "活跃的",
+ "desc": "应用于每个质押周期开始的两小时时段,以改善周期之间的存款和提款过程",
+ "title": "冷却时间"
},
- "frequency" : {
- "label" : "奖励频率",
- "value" : "每%{count}小时"
+ "frequency": {
+ "label": "奖励频率",
+ "value": "每%{count}小时"
},
- "min_deposit" : {
- "label" : "最小存款",
- "value" : "%{value} TON"
+ "min_deposit": {
+ "label": "最小存款",
+ "value": "%{value} TON"
},
- "next_cycle" : {
- "desc" : "所有交易在周期结束后生效",
- "desc_liquid" : "所有提款请求在周期结束后生效",
- "time" : "在%{time}内",
- "title" : "下一个周期"
+ "next_cycle": {
+ "desc": "所有交易在周期结束后生效",
+ "desc_liquid": "所有提款请求在周期结束后生效",
+ "time": "在%{time}内",
+ "title": "下一个周期"
},
- "pendingDeposit" : "待处理的存款",
- "pendingWithdraw" : "待处理的提款",
- "pool_address" : {
- "label" : "质押池地址"
+ "pendingDeposit": "待处理的存款",
+ "pendingWithdraw": "待处理的提款",
+ "pool_address": {
+ "label": "质押池地址"
},
- "readyWithdraw" : "提款已准备好",
- "show_details" : "详细信息",
- "tap_to_collect" : "点击收集"
+ "readyWithdraw": "提款已准备好",
+ "show_details": "详细信息",
+ "tap_to_collect": "点击收集"
},
- "get_withdrawal" : "收到提款",
- "other" : "其他",
- "recommended" : "最高利息",
- "rewards" : {
- "after_top_up" : "充值后",
- "current" : "当前的",
- "title" : "您的年度奖励",
- "value" : "≈ %{value} TON"
+ "get_withdrawal": "收到提款",
+ "other": "其他",
+ "recommended": "最高利息",
+ "rewards": {
+ "after_top_up": "充值后",
+ "current": "当前的",
+ "title": "您的年度奖励",
+ "value": "≈ %{value} TON"
},
- "staking_desc" : "最低存款从%{minStake} TON开始。\n赚取高达%{maxApy}%的收益。",
- "staking_pool_desc" : "年化收益率 ≈ %{apy}%",
- "title" : "质押",
- "top_up" : "充值",
- "transaction" : "交易",
- "warning" : {
- "about" : "关于%{name}",
- "desc" : "质押基于第三方智能合约。我们不对其工作负责。",
- "title" : "警告"
+ "staking_desc": "最低存款从%{minStake} TON开始。\n赚取高达%{maxApy}%的收益。",
+ "staking_pool_desc": "年化收益率 ≈ %{apy}%",
+ "title": "质押",
+ "top_up": "充值",
+ "transaction": "交易",
+ "warning": {
+ "about": "关于%{name}",
+ "desc": "质押基于第三方智能合约。我们不对其工作负责。",
+ "title": "警告"
},
- "widget_desc" : "在您的TONs上赚取高达 %{apy}%的收益",
- "withdraw" : "提款",
- "withdrawal_fee_warning" : {
- "continue" : "继续操作",
- "message" : "请至少在您的余额上保留{{amount}} TON。",
- "title" : "您的资金不足以提款"
+ "widget_desc": "在您的TONs上赚取高达 %{apy}%的收益",
+ "withdraw": "提款",
+ "withdrawal_fee_warning": {
+ "continue": "继续操作",
+ "message": "请至少在您的余额上保留{{amount}} TON。",
+ "title": "您的资金不足以提款"
},
- "withdrawal_request" : "提款请求"
- },
- "subscription_back_to_merchant_button" : "返回",
- "subscription_back_to_merchant_caption" : "交易正在处理中。您的订阅很快就会生效。",
- "subscription_back_to_merchant_name" : "返回到%{merchantName}",
- "subscription_back_to_merchant_title" : "返回到频道?",
- "subscription_cancel" : "取消订阅",
- "subscription_cancel_alert_cancel_btn" : "现在不",
- "subscription_cancel_alert_caption" : "如果您现在取消,您仍然可以在%{nextBill}之前访问您的订阅。",
- "subscription_cancel_alert_submit_btn" : "是的,取消",
- "subscription_cancel_alert_title" : "取消订阅?",
- "subscription_expiring" : "到期",
- "subscription_fee" : "费用",
- "subscription_next_bill" : "下一次账单",
- "subscription_open_merchant" : "在Telegram中打开",
- "subscription_period" : "间隔",
- "subscription_period_custom" : "每%{period}",
- "subscription_period_day" : "每日",
- "subscription_period_half_year" : "每半年",
- "subscription_period_hour" : "每小时",
- "subscription_period_month" : "每月",
- "subscription_period_quarter" : "每季度",
- "subscription_period_week" : "每周",
- "subscription_period_weeks" : "每%{count}周",
- "subscription_period_year" : "每年",
- "subscription_price" : "价格",
- "subscription_sent" : "交易已发送",
- "subscriptions_item_caption" : "%{price} TON, 下一次账单在%{nextBill}",
- "subscriptions_item_caption_expired" : "在%{date}到期",
- "subscriptions_item_caption_expiring" : "%{price} TON, 在%{date}到期",
- "subscriptions_section_active" : "活跃",
- "subscriptions_section_expired" : "已过期",
- "subscription_started" : "已开始订阅",
- "subscriptions_title" : "订阅",
- "subscription_subscribe" : "订阅",
- "subscription_title" : "订阅",
- "subscription_unsubscribe" : "取消订阅",
- "success" : "成功!",
- "swap_title" : "交换",
- "tab_browser" : "浏览器",
- "tab_nft" : "NFTs",
- "tab_settings" : "设置",
- "tab_swap" : "交换",
- "tab_wallet" : "钱包",
- "today" : "今天",
- "tonkeeper_pro" : "Tonkeeper Pro",
- "ton_login_back_to_button" : "返回到%{name}",
- "ton_login_caption" : "%{name}正在请求访问您的钱包地址",
- "ton_login_connect_button" : "连接钱包",
- "ton_login_notice" : "连接钱包之前,请务必检查服务地址。",
- "ton_login_success" : "完成",
- "ton_login_title" : "连接到%domain?",
- "transaction_bid_collection_name" : "发行者",
- "transaction_bid_date" : "出价日期 %{date}",
- "transaction_bid_dns" : "名称",
- "transaction_buy_date" : "购买日期 %{date}",
- "transaction_buy_status_failed" : "失败",
- "transaction_buy_status_pending" : "待处理",
- "transaction_buy_status_success" : "成功",
- "transaction_confirmations" : "确认",
- "transaction_confirm_bid" : "确认出价",
- "transaction_contract_deploy_date" : "合约部署日期 %{date}",
- "transaction_copy_caution" : "小心外部链接!!!永远不要将你的密钥/助记词提供给第三者 — 否则你可能会失去所有的资金。\n\n- - -\n\n",
- "transactionDetails" : {
- "address" : "地址",
- "bid_collection_name" : "发行者",
- "bid_date" : "在 %{time} 出价",
- "bid_name" : "名称",
- "comment" : "评论",
- "operation" : "操作",
- "payload" : "有效载荷",
- "purchase_date" : "在 %{time} 购买",
- "received_date" : "在 %{time} 收到",
- "recipient" : "接收者",
- "recipient_address" : "接收者地址",
- "sender" : "发送者",
- "sender_address" : "发送者地址",
- "sent_date" : "在 %{time} 发送",
- "spam" : "垃圾邮件",
- "swapped_date" : "在 %{time} 交换",
- "transaction" : "交易"
- },
- "transaction_exchange_from_currency" : "从",
- "transaction_fee" : "手续费",
- "transaction_hash" : "交易",
- "transaction_merchant" : "商家",
- "transaction_message" : "消息",
- "transaction_purchase_id" : "购买ID",
- "transaction_receive_date" : "接收日期 %{date}",
- "transaction_recipient" : "收款方",
- "transaction_recipient_address" : "收款方地址",
- "transaction_refund" : "退款",
- "transactions" : {
- "bid" : "出价",
- "contract_deploy" : "部署合约",
- "failed" : "失败",
- "nft_purchase" : "NFT购买",
- "smartcontract_exec" : "调用合约",
- "spam" : "垃圾消息",
- "subscription" : "已订阅",
- "swap" : "交换",
- "unknown" : "未知",
- "unknown_description" : "发生了一些事情,但我们无法识别",
- "unsubscription" : "已退订",
- "wallet_initialized" : "钱包已初始化"
- },
- "transaction_sender" : "付款方",
- "transaction_sender_address" : "付款方地址",
- "transaction_send_more_button" : "向此接收方发送更多",
- "transaction_sent_date" : "发送日期 %{date}",
- "transaction_show_subscription_button" : "查看订阅",
- "transaction_status" : "状态",
- "transaction_subscription" : "订阅",
- "transaction_subscription_date" : "扣费日期 %{date}",
- "transaction_transfer_name" : "转账名称",
- "transaction_type_bid" : "出价",
- "transaction_type_bounced" : "已退回",
- "transaction_type_buy" : "已购买",
- "transaction_type_contract_deploy" : "合约部署",
- "transaction_type_from" : "来自",
- "transaction_type_new_subscriber" : "新订阅者",
- "transaction_type_pending" : "支付中",
- "transaction_type_receive" : "已接收",
- "transaction_type_sent" : "已发送",
- "transaction_type_subscriber_lost" : "订阅者丢失",
- "transaction_type_subscription" : "已订阅",
- "transaction_type_to" : "到",
- "transaction_type_unsubscription" : "已取消订阅",
- "transaction_type_wallet_initialized" : "已初始化钱包",
- "transaction_unsubscription" : "取消订阅",
- "transaction_unsubscription_date" : "取消订阅日期 %{date}",
- "transaction_view_in_explorer" : "在浏览器中查看",
- "transaction_wallet_initialized_date" : "钱包初始化日期 %{date}",
- "transaction_your_bid" : "你的出价",
- "transfer_deeplink_address_error" : "收件人地址不正确",
- "transfer_deeplink_amount_error" : "金额请求不正确",
- "transfer_deeplink_nft_address_error" : "NFT地址不正确",
- "transfer_from_old_wallet_btn" : "转移",
- "transfer_from_old_wallet_caption" : "Tonkeeper将从您的旧地址转移所有硬币到您的当前地址。",
- "transfer_from_old_wallet_in_progress" : "转移正在进行中",
- "transfer_from_old_wallet_title" : "转移到当前地址",
- "txActions" : {
- "amount" : "金额",
- "fee" : "费用",
- "refund" : "退款",
- "signRaw" : {
- "addressMismatch" : {
- "wrongVersion" : {
- "close" : "取消",
- "description" : "切换您的活动地址至%{version}以确认此操作。",
- "switch" : "切换并继续",
- "title" : "您钱包的另一个地址的操作"
+ "withdrawal_request": "提款请求"
+ },
+ "start_screen": {
+ "caption": "创建一个新钱包或添加现有钱包",
+ "create_wallet_button": "创建新钱包",
+ "import_wallet_button": "导入现有钱包"
+ },
+ "stop_watch": "删除观察账户",
+ "subscription_back_to_merchant_button": "返回",
+ "subscription_back_to_merchant_caption": "交易正在处理中。您的订阅很快就会生效。",
+ "subscription_back_to_merchant_name": "返回到%{merchantName}",
+ "subscription_back_to_merchant_title": "返回到频道?",
+ "subscription_cancel": "取消订阅",
+ "subscription_cancel_alert_cancel_btn": "现在不",
+ "subscription_cancel_alert_caption": "如果您现在取消,您仍然可以在%{nextBill}之前访问您的订阅。",
+ "subscription_cancel_alert_submit_btn": "是的,取消",
+ "subscription_cancel_alert_title": "取消订阅?",
+ "subscription_expiring": "到期",
+ "subscription_fee": "费用",
+ "subscription_next_bill": "下一次账单",
+ "subscription_open_merchant": "在Telegram中打开",
+ "subscription_period": "间隔",
+ "subscription_period_custom": "每%{period}",
+ "subscription_period_day": "每日",
+ "subscription_period_half_year": "每半年",
+ "subscription_period_hour": "每小时",
+ "subscription_period_month": "每月",
+ "subscription_period_quarter": "每季度",
+ "subscription_period_week": "每周",
+ "subscription_period_weeks": "每%{count}周",
+ "subscription_period_year": "每年",
+ "subscription_price": "价格",
+ "subscription_sent": "交易已发送",
+ "subscriptions_item_caption": "%{price} TON, 下一次账单在%{nextBill}",
+ "subscriptions_item_caption_expired": "在%{date}到期",
+ "subscriptions_item_caption_expiring": "%{price} TON, 在%{date}到期",
+ "subscriptions_section_active": "活跃",
+ "subscriptions_section_expired": "已过期",
+ "subscription_started": "已开始订阅",
+ "subscriptions_title": "订阅",
+ "subscription_subscribe": "订阅",
+ "subscription_title": "订阅",
+ "subscription_unsubscribe": "取消订阅",
+ "success": "成功!",
+ "swap_title": "交换",
+ "tab_browser": "浏览器",
+ "tab_nft": "NFTs",
+ "tab_settings": "设置",
+ "tab_swap": "交换",
+ "tab_wallet": "钱包",
+ "today": "今天",
+ "tonkeeper_pro": "Tonkeeper Pro",
+ "ton_login_back_to_button": "返回到%{name}",
+ "ton_login_caption": "%{name}正在请求访问您的钱包地址",
+ "ton_login_connect_button": "连接钱包",
+ "ton_login_notice": "连接钱包之前,请务必检查服务地址。",
+ "ton_login_success": "完成",
+ "ton_login_title": "连接到%{0, number}omain?",
+ "transaction_bid_collection_name": "发行者",
+ "transaction_bid_date": "出价日期 %{date}",
+ "transaction_bid_dns": "名称",
+ "transaction_buy_date": "购买日期 %{date}",
+ "transaction_buy_status_failed": "失败",
+ "transaction_buy_status_pending": "待处理",
+ "transaction_buy_status_success": "成功",
+ "transaction_confirmations": "确认",
+ "transaction_confirm_bid": "确认出价",
+ "transaction_contract_deploy_date": "合约部署日期 %{date}",
+ "transaction_copy_caution": "小心外部链接!!!永远不要将你的密钥/助记词提供给第三者 — 否则你可能会失去所有的资金。\n\n- - -\n\n",
+ "transactionDetails": {
+ "address": "地址",
+ "bid_collection_name": "发行者",
+ "bid_date": "在 %{time} 出价",
+ "bid_name": "名称",
+ "comment": "评论",
+ "operation": "操作",
+ "payload": "有效载荷",
+ "purchase_date": "在 %{time} 购买",
+ "received_date": "在 %{time} 收到",
+ "recipient": "接收者",
+ "recipient_address": "接收者地址",
+ "sender": "发送者",
+ "sender_address": "发送者地址",
+ "sent_date": "在 %{time} 发送",
+ "spam": "垃圾邮件",
+ "swapped_date": "在 %{time} 交换",
+ "transaction": "交易"
+ },
+ "transaction_exchange_from_currency": "从",
+ "transaction_fee": "手续费",
+ "transaction_hash": "交易",
+ "transaction_merchant": "商家",
+ "transaction_message": "消息",
+ "transaction_purchase_id": "购买ID",
+ "transaction_receive_date": "接收日期 %{date}",
+ "transaction_recipient": "收款方",
+ "transaction_recipient_address": "收款方地址",
+ "transaction_refund": "退款",
+ "transactions": {
+ "bid": "出价",
+ "contract_deploy": "部署合约",
+ "failed": "失败",
+ "nft_purchase": "NFT购买",
+ "smartcontract_exec": "调用合约",
+ "spam": "垃圾消息",
+ "subscription": "已订阅",
+ "swap": "交换",
+ "unknown": "未知",
+ "unknown_description": "发生了一些事情,但我们无法识别",
+ "unsubscription": "已退订",
+ "wallet_initialized": "钱包已初始化"
+ },
+ "transaction_sender": "付款方",
+ "transaction_sender_address": "付款方地址",
+ "transaction_send_more_button": "向此接收方发送更多",
+ "transaction_sent_date": "发送日期 %{date}",
+ "transaction_show_subscription_button": "查看订阅",
+ "transaction_status": "状态",
+ "transaction_subscription": "订阅",
+ "transaction_subscription_date": "扣费日期 %{date}",
+ "transaction_transfer_name": "转账名称",
+ "transaction_type_bid": "出价",
+ "transaction_type_bounced": "已退回",
+ "transaction_type_buy": "已购买",
+ "transaction_type_contract_deploy": "合约部署",
+ "transaction_type_from": "来自",
+ "transaction_type_new_subscriber": "新订阅者",
+ "transaction_type_pending": "支付中",
+ "transaction_type_receive": "已接收",
+ "transaction_type_sent": "已发送",
+ "transaction_type_subscriber_lost": "订阅者丢失",
+ "transaction_type_subscription": "已订阅",
+ "transaction_type_to": "到",
+ "transaction_type_unsubscription": "已取消订阅",
+ "transaction_type_wallet_initialized": "已初始化钱包",
+ "transaction_unsubscription": "取消订阅",
+ "transaction_unsubscription_date": "取消订阅日期 %{date}",
+ "transaction_view_in_explorer": "在浏览器中查看",
+ "transaction_wallet_initialized_date": "钱包初始化日期 %{date}",
+ "transaction_your_bid": "你的出价",
+ "transfer_deeplink_address_error": "收件人地址不正确",
+ "transfer_deeplink_amount_error": "金额请求不正确",
+ "transfer_deeplink_nft_address_error": "NFT地址不正确",
+ "transfer_from_old_wallet_btn": "转移",
+ "transfer_from_old_wallet_caption": "Tonkeeper将从您的旧地址转移所有硬币到您的当前地址。",
+ "transfer_from_old_wallet_in_progress": "转移正在进行中",
+ "transfer_from_old_wallet_title": "转移到当前地址",
+ "txActions": {
+ "amount": "金额",
+ "fee": "费用",
+ "refund": "退款",
+ "signRaw": {
+ "addressMismatch": {
+ "wrongVersion": {
+ "close": "取消",
+ "description": "切换您的活动地址至%{version}以确认此操作。",
+ "switch": "切换并继续",
+ "title": "您钱包的另一个地址的操作"
},
- "wrongWallet" : {
- "close" : "好的",
- "description" : "登录到另一个钱包%{address}然后再试。",
- "title" : "另一个钱包的操作"
+ "wrongWallet": {
+ "close": "好的",
+ "description": "登录到另一个钱包%{address}然后再试。",
+ "title": "另一个钱包的操作"
}
},
- "comment" : "评论",
- "insufficientFunds" : {
- "rechargeBattery" : "给电池充电",
- "rechargeWallet" : "充值钱包",
- "title" : "资金不足",
- "toBePaid" : "支付金额: %{amount} %{currency}\n",
- "withFees" : "+ 区块链费用。\n",
- "yourBalance" : "您的余额: %{balance} %{currency}。"
+ "comment": "评论",
+ "insufficientFunds": {
+ "rechargeBattery": "给电池充电",
+ "rechargeWallet": "充值钱包",
+ "title": "资金不足",
+ "toBePaid": "支付金额: %{amount} %{currency}\n",
+ "withFees": "+ 区块链费用。\n",
+ "yourBalance": "您的余额: %{balance} %{currency}。"
},
- "recipient" : "收款方",
- "title" : "确认交易",
- "totalFee" : "总费用",
- "totalRefund" : "总退款",
- "types" : {
- "contractDeploy" : "合同部署",
- "jettonTransfer" : "代币转移",
- "nftItemTransfer" : "NFT转移",
- "subscribe" : "订阅",
- "tonTransfer" : "TON转移",
- "unknownTransaction" : "未知交易",
- "unSubscribe" : "退订"
+ "recipient": "收款方",
+ "title": "确认交易",
+ "totalFee": "总费用",
+ "totalRefund": "总退款",
+ "types": {
+ "contractDeploy": "合同部署",
+ "jettonTransfer": "代币转移",
+ "nftItemTransfer": "NFT转移",
+ "subscribe": "订阅",
+ "tonTransfer": "TON转移",
+ "unknownTransaction": "未知交易",
+ "unSubscribe": "退订"
},
- "warning_caption" : "Tonkeeper无法完全验证此交易的结果。请确保您信任接收者。",
- "warning_title" : "警告",
- "wrongTime" : {
- "button" : "打开设置",
- "description" : "似乎您的设备时钟与网络不同步。打开设备设置并启用自动时间和日期。",
- "title" : "时钟未同步"
+ "warning_caption": "Tonkeeper无法完全验证此交易的结果。请确保您信任接收者。",
+ "warning_title": "警告",
+ "wrongTime": {
+ "button": "打开设置",
+ "description": "似乎您的设备时钟与网络不同步。打开设备设置并启用自动时间和日期。",
+ "title": "时钟未同步"
}
}
},
- "update" : {
- "description" : "Tonkeeper的新版本现已可用。您现在可以下载它。",
- "download" : "下载",
- "downloading" : "下载中... {{progress}}%",
- "mb" : "{{size}} MB",
- "remindLater" : "稍后提醒我",
- "retry" : "下载错误。点击重试。",
- "tap" : "点击更新",
- "title" : "更新Tonkeeper",
- "version" : "版本 {{version}}"
- },
- "username_issued_by_telegram" : "由Telegram发布。",
- "username_manage_name_button" : "管理名称",
- "wallet_about" : "关于",
- "wallet_buy" : "购买",
- "wallet" : {
- "buy_btn" : "购买TON",
- "collectibles_tab_lable" : "收藏品",
- "edit_tokens_btn" : "编辑",
- "old_wallets_title" : "旧钱包",
- "old_wallet_title" : "旧钱包",
- "receive_btn" : "接收",
- "screen_title" : "钱包",
- "send_btn" : "发送",
- "swap_btn" : "交换",
- "tonkens_tab_lable" : "代币"
- },
- "wallet_chat" : "聊天室",
- "wallet_community" : "社区",
- "wallet_hours_symbol" : "h",
- "wallet_old_balance" : "老钱包:",
- "wallet_receive" : "接收",
- "wallet_sell" : "出售",
- "wallet_send" : "发送",
- "wallet_source_code" : "源代码",
- "wallet_swap" : "交换",
- "wallet_title" : "钱包",
- "wallet_toncommunity_chat_link" : "https://t.me/toncoin_chat",
- "wallet_toncommunity_link" : "https://t.me/toncoin",
- "yesterday" : "昨天"
+ "update": {
+ "description": "Tonkeeper的新版本现已可用。您现在可以下载它。",
+ "download": "下载",
+ "downloading": "下载中... {{progress}}%",
+ "mb": "{{size}} MB",
+ "remindLater": "稍后提醒我",
+ "retry": "下载错误。点击重试。",
+ "tap": "点击更新",
+ "title": "更新Tonkeeper",
+ "version": "版本 {{version}}"
+ },
+ "username_issued_by_telegram": "由Telegram发布。",
+ "username_manage_name_button": "管理名称",
+ "wallet_about": "关于",
+ "wallet_buy": "购买",
+ "wallet": {
+ "buy_btn": "购买TON",
+ "collectibles_tab_lable": "收藏品",
+ "edit_tokens_btn": "编辑",
+ "old_wallets_title": "旧钱包",
+ "old_wallet_title": "旧钱包",
+ "receive_btn": "接收",
+ "screen_title": "钱包",
+ "send_btn": "发送",
+ "swap_btn": "交换",
+ "tonkens_tab_lable": "代币"
+ },
+ "wallet_chat": "聊天室",
+ "wallet_community": "社区",
+ "wallet_hours_symbol": "h",
+ "wallet_old_balance": "老钱包:",
+ "wallet_receive": "接收",
+ "wallets": "钱包",
+ "wallet_sell": "出售",
+ "wallet_send": "发送",
+ "wallet_source_code": "源代码",
+ "wallet_swap": "交换",
+ "wallet_title": "钱包",
+ "wallet_toncommunity_chat_link": "https://t.me/toncoin_chat",
+ "wallet_toncommunity_link": "https://t.me/toncoin",
+ "watch_only": "仅限观察",
+ "yesterday": "昨天"
}
diff --git a/packages/shared/modals/AboutRiskAmountModal.tsx b/packages/shared/modals/AboutRiskAmountModal.tsx
new file mode 100644
index 000000000..facb649ae
--- /dev/null
+++ b/packages/shared/modals/AboutRiskAmountModal.tsx
@@ -0,0 +1,70 @@
+import React, { memo } from 'react';
+import { Button, Modal, Spacer, Text, View } from '@tonkeeper/uikit';
+import { Steezy } from '@tonkeeper/uikit';
+import { navigation, SheetActions, useNavigation } from '@tonkeeper/router';
+import { t } from '@tonkeeper/shared/i18n';
+
+export interface AboutRiskAmountModalProps {
+ title: string;
+ withNft?: boolean;
+}
+
+export const AboutRiskAmountModal = memo((props) => {
+ const nav = useNavigation();
+ return (
+
+
+
+
+
+ {props.title}
+
+
+
+ {t(
+ props.withNft
+ ? 'about_risk_modal.description_with_nft'
+ : 'about_risk_modal.description',
+ )}
+
+
+
+
+
+
+
+
+
+
+
+ );
+});
+
+export function openAboutRiskAmountModal(title: string, withNft?: boolean) {
+ return navigation.push('SheetsProvider', {
+ $$action: SheetActions.ADD,
+ component: AboutRiskAmountModal,
+ params: { title, withNft },
+ path: 'AboutRiskAmountModal',
+ });
+}
+
+const styles = Steezy.create({
+ wrap: {
+ alignItems: 'center',
+ paddingHorizontal: 32,
+ textAlign: 'center',
+ paddingTop: 48,
+ },
+ footerWrap: {
+ paddingHorizontal: 16,
+ },
+ checkboxWithLabel: {
+ flexDirection: 'row',
+ justifyContent: 'center',
+ alignItems: 'center',
+ },
+ buttonContainer: {
+ paddingHorizontal: 16,
+ },
+});
diff --git a/packages/shared/modals/ActivityActionModal/RechargeByPromoModal.tsx b/packages/shared/modals/ActivityActionModal/RechargeByPromoModal.tsx
index 11241c130..5b7a0bf06 100644
--- a/packages/shared/modals/ActivityActionModal/RechargeByPromoModal.tsx
+++ b/packages/shared/modals/ActivityActionModal/RechargeByPromoModal.tsx
@@ -42,7 +42,6 @@ export const RechargeByPromoModal = memo(() => {
/>
-
diff --git a/packages/shared/modals/SwitchWalletModal.tsx b/packages/shared/modals/SwitchWalletModal.tsx
index 0ec2d5da0..5f416a363 100644
--- a/packages/shared/modals/SwitchWalletModal.tsx
+++ b/packages/shared/modals/SwitchWalletModal.tsx
@@ -6,6 +6,7 @@ import { tk } from '@tonkeeper/mobile/src/wallet';
import { t } from '../i18n';
import { formatter } from '../formatter';
import { WalletListItem } from '../components';
+import { HideableAmount } from '@tonkeeper/mobile/src/core/HideableAmount/HideableAmount';
interface Props {
selected?: string;
@@ -47,7 +48,11 @@ export const SwitchWalletModal: FC = memo((props) => {
key={wallet.identifier}
wallet={wallet}
onPress={handlePress(wallet.identifier)}
- subtitle={formatter.format(wallet.totalFiat, { currency })}
+ subtitle={
+
+ {formatter.format(wallet.totalFiat, { currency })}
+
+ }
rightContent={
selectedIdentifier === wallet.identifier && (
diff --git a/packages/shared/package.json b/packages/shared/package.json
index 00560e66f..b83e4b9a8 100644
--- a/packages/shared/package.json
+++ b/packages/shared/package.json
@@ -4,7 +4,7 @@
"private": true,
"scripts": {
"push_locales": "tolgee push ./i18n/locales",
- "pull_locales": "tolgee pull ./i18n/locales --namespaces tonkeeper",
+ "pull_locales": "tolgee pull ./i18n/locales --namespaces tonkeeper && node scripts/fix_translations.js",
"generate_locale": "cd i18n/locales/tonkeeper && bun translate.js"
},
"dependencies": {
diff --git a/packages/shared/scripts/fix_translations.js b/packages/shared/scripts/fix_translations.js
new file mode 100644
index 000000000..ee5dc5a32
--- /dev/null
+++ b/packages/shared/scripts/fix_translations.js
@@ -0,0 +1,58 @@
+const fs = require('fs');
+const path = require('path');
+
+const pathExp = __dirname.split('/');
+pathExp.pop();
+
+// Specify the directory of your JSON files here
+const directoryPath = `${pathExp.join('/')}/i18n/locales/tonkeeper`;
+
+// Function to recursively traverse and fix values in an object or array
+function traverseAndFix(obj) {
+ for (let key in obj) {
+ if (typeof obj[key] === 'string') {
+ // Replace '{{'value'}}' with {{value}}
+ obj[key] = obj[key].replace(/'\{\{\s*'([^}]+)'\s*\}\}'/g, '{{$1}}');
+
+ // Replace {value} with %{value}, excluding already existing %{value} or {{value}}
+ obj[key] = obj[key].replace(/(? {
+ if (err) {
+ console.error(`Error reading file from disk: ${err}`);
+ } else {
+ // Parse the JSON data
+ let jsonData = JSON.parse(data);
+
+ // Recursively fix the translations
+ traverseAndFix(jsonData);
+
+ // Write the modified JSON back to the file
+ fs.writeFile(filePath, JSON.stringify(jsonData, null, 2), 'utf8', (err) => {
+ if (err) return console.log(err);
+ console.log(`File has been saved: ${filePath}`);
+ });
+ }
+ });
+}
+
+// Read the directory and apply the fix to each JSON file
+fs.readdir(directoryPath, (err, files) => {
+ if (err) {
+ console.error(`Could not list the directory: ${err}`);
+ return;
+ }
+
+ files.forEach((file) => {
+ if (path.extname(file) === '.json') {
+ fixTranslations(path.join(directoryPath, file));
+ }
+ });
+});
diff --git a/packages/shared/utils/blockchain.ts b/packages/shared/utils/blockchain.ts
index c65fb7cc2..342843c02 100644
--- a/packages/shared/utils/blockchain.ts
+++ b/packages/shared/utils/blockchain.ts
@@ -1,8 +1,19 @@
import { config } from '@tonkeeper/mobile/src/config';
import { tk } from '@tonkeeper/mobile/src/wallet';
-import { ContentType } from '@tonkeeper/core/src/TonAPI';
+import { ContentType, ServiceStatus } from '@tonkeeper/core/src/TonAPI';
+import { TransactionService } from '@tonkeeper/core';
+import { t } from '../i18n';
+
+export class NetworkOverloadedError extends Error {}
export async function sendBoc(boc, attemptWithRelayer = true) {
+ const { rest_online, indexing_latency } =
+ (await tk.wallet.tonapi.status.reduceIndexingLatency()) as ServiceStatus;
+
+ if (!rest_online || indexing_latency > TransactionService.TTL - 30) {
+ throw new NetworkOverloadedError(t('network_overloaded_error'));
+ }
+
try {
if (
!attemptWithRelayer ||
@@ -11,12 +22,7 @@ export async function sendBoc(boc, attemptWithRelayer = true) {
) {
throw new Error('Battery disabled');
}
- if (
- !tk.wallet.battery?.state?.data?.balance ||
- tk.wallet.battery.state.data.balance === '0'
- ) {
- throw new Error('Zero balance');
- }
+
return await tk.wallet.battery.sendMessage(boc);
} catch (err) {
return await tk.wallet.tonapi.blockchain.sendBlockchainMessage(
@@ -28,7 +34,12 @@ export async function sendBoc(boc, attemptWithRelayer = true) {
}
}
-export async function emulateBoc(boc, params?, attemptWithRelayer = false) {
+export async function emulateBoc(
+ boc,
+ params?,
+ attemptWithRelayer = false,
+ forceRelayer = false,
+) {
try {
if (
!attemptWithRelayer ||
@@ -37,14 +48,16 @@ export async function emulateBoc(boc, params?, attemptWithRelayer = false) {
) {
throw new Error('Battery disabled');
}
+
if (
- !tk.wallet.battery?.state?.data?.balance ||
- tk.wallet.battery.state.data.balance === '0'
+ !forceRelayer &&
+ (!tk.wallet.battery?.state?.data?.balance ||
+ tk.wallet.battery.state.data.balance === '0')
) {
throw new Error('Zero balance');
}
- const emulateResult = await tk.wallet.battery.emulate(boc);
- return { emulateResult, battery: true };
+ const { consequences, withBattery } = await tk.wallet.battery.emulate(boc);
+ return { emulateResult: consequences, battery: withBattery };
} catch (err) {
const emulateResult = await tk.wallet.tonapi.wallet.emulateMessageToWallet({
boc,
diff --git a/packages/uikit/assets/icons/png/ic-arrow-down-outline-28@4x.png b/packages/uikit/assets/icons/png/ic-arrow-down-outline-28@4x.png
new file mode 100644
index 000000000..1c2e6c5f7
Binary files /dev/null and b/packages/uikit/assets/icons/png/ic-arrow-down-outline-28@4x.png differ
diff --git a/packages/uikit/assets/icons/png/ic-arrow-right-outline-28@4x.png b/packages/uikit/assets/icons/png/ic-arrow-right-outline-28@4x.png
new file mode 100644
index 000000000..5620fbf3b
Binary files /dev/null and b/packages/uikit/assets/icons/png/ic-arrow-right-outline-28@4x.png differ
diff --git a/packages/uikit/assets/icons/png/ic-arrow-up-outline-28@4x.png b/packages/uikit/assets/icons/png/ic-arrow-up-outline-28@4x.png
new file mode 100644
index 000000000..12fb902fb
Binary files /dev/null and b/packages/uikit/assets/icons/png/ic-arrow-up-outline-28@4x.png differ
diff --git a/packages/uikit/assets/icons/png/ic-bank-card-32@4x.png b/packages/uikit/assets/icons/png/ic-bank-card-32@4x.png
new file mode 100644
index 000000000..72d2d8c86
Binary files /dev/null and b/packages/uikit/assets/icons/png/ic-bank-card-32@4x.png differ
diff --git a/packages/uikit/assets/icons/png/ic-chinese-yuan-circle-32@4x.png b/packages/uikit/assets/icons/png/ic-chinese-yuan-circle-32@4x.png
new file mode 100644
index 000000000..e3e82c42c
Binary files /dev/null and b/packages/uikit/assets/icons/png/ic-chinese-yuan-circle-32@4x.png differ
diff --git a/packages/uikit/assets/icons/png/ic-dollar-circle-32@4x.png b/packages/uikit/assets/icons/png/ic-dollar-circle-32@4x.png
new file mode 100644
index 000000000..7746a294d
Binary files /dev/null and b/packages/uikit/assets/icons/png/ic-dollar-circle-32@4x.png differ
diff --git a/packages/uikit/assets/icons/png/ic-euro-circle-32@4x.png b/packages/uikit/assets/icons/png/ic-euro-circle-32@4x.png
new file mode 100644
index 000000000..60ef4871c
Binary files /dev/null and b/packages/uikit/assets/icons/png/ic-euro-circle-32@4x.png differ
diff --git a/packages/uikit/assets/icons/png/ic-flash-32@4x.png b/packages/uikit/assets/icons/png/ic-flash-32@4x.png
new file mode 100644
index 000000000..ca78d7946
Binary files /dev/null and b/packages/uikit/assets/icons/png/ic-flash-32@4x.png differ
diff --git a/packages/uikit/assets/icons/png/ic-flash-circle-32@4x.png b/packages/uikit/assets/icons/png/ic-flash-circle-32@4x.png
new file mode 100644
index 000000000..5525e9aa9
Binary files /dev/null and b/packages/uikit/assets/icons/png/ic-flash-circle-32@4x.png differ
diff --git a/packages/uikit/assets/icons/png/ic-gear-32@4x.png b/packages/uikit/assets/icons/png/ic-gear-32@4x.png
new file mode 100644
index 000000000..aa054d339
Binary files /dev/null and b/packages/uikit/assets/icons/png/ic-gear-32@4x.png differ
diff --git a/packages/uikit/assets/icons/png/ic-gear-outline-28@4x.png b/packages/uikit/assets/icons/png/ic-gear-outline-28@4x.png
new file mode 100644
index 000000000..19a67e389
Binary files /dev/null and b/packages/uikit/assets/icons/png/ic-gear-outline-28@4x.png differ
diff --git a/packages/uikit/assets/icons/png/ic-hand-raised-32@4x.png b/packages/uikit/assets/icons/png/ic-hand-raised-32@4x.png
new file mode 100644
index 000000000..5ae4cadf7
Binary files /dev/null and b/packages/uikit/assets/icons/png/ic-hand-raised-32@4x.png differ
diff --git a/packages/uikit/assets/icons/png/ic-hare-32@4x.png b/packages/uikit/assets/icons/png/ic-hare-32@4x.png
new file mode 100644
index 000000000..d88e5557f
Binary files /dev/null and b/packages/uikit/assets/icons/png/ic-hare-32@4x.png differ
diff --git a/packages/uikit/assets/icons/png/ic-inbox-32@4x.png b/packages/uikit/assets/icons/png/ic-inbox-32@4x.png
new file mode 100644
index 000000000..1bfccade0
Binary files /dev/null and b/packages/uikit/assets/icons/png/ic-inbox-32@4x.png differ
diff --git a/packages/uikit/assets/icons/png/ic-indian-rupee-circle-32@4x.png b/packages/uikit/assets/icons/png/ic-indian-rupee-circle-32@4x.png
new file mode 100644
index 000000000..dc5a0df69
Binary files /dev/null and b/packages/uikit/assets/icons/png/ic-indian-rupee-circle-32@4x.png differ
diff --git a/packages/uikit/assets/icons/png/ic-key-32@4x.png b/packages/uikit/assets/icons/png/ic-key-32@4x.png
new file mode 100644
index 000000000..c52bec762
Binary files /dev/null and b/packages/uikit/assets/icons/png/ic-key-32@4x.png differ
diff --git a/packages/uikit/assets/icons/png/ic-leaf-32@4x.png b/packages/uikit/assets/icons/png/ic-leaf-32@4x.png
new file mode 100644
index 000000000..543876fd4
Binary files /dev/null and b/packages/uikit/assets/icons/png/ic-leaf-32@4x.png differ
diff --git a/packages/uikit/assets/icons/png/ic-lock-32@4x.png b/packages/uikit/assets/icons/png/ic-lock-32@4x.png
new file mode 100644
index 000000000..e5de3f8a6
Binary files /dev/null and b/packages/uikit/assets/icons/png/ic-lock-32@4x.png differ
diff --git a/packages/uikit/assets/icons/png/ic-magnifying-glass-circle-32@4x.png b/packages/uikit/assets/icons/png/ic-magnifying-glass-circle-32@4x.png
new file mode 100644
index 000000000..38ea5f5db
Binary files /dev/null and b/packages/uikit/assets/icons/png/ic-magnifying-glass-circle-32@4x.png differ
diff --git a/packages/uikit/assets/icons/png/ic-minus-outline-28@4x.png b/packages/uikit/assets/icons/png/ic-minus-outline-28@4x.png
new file mode 100644
index 000000000..5596c68f6
Binary files /dev/null and b/packages/uikit/assets/icons/png/ic-minus-outline-28@4x.png differ
diff --git a/packages/uikit/assets/icons/png/ic-plus-outline-28@4x.png b/packages/uikit/assets/icons/png/ic-plus-outline-28@4x.png
new file mode 100644
index 000000000..0e34cbf40
Binary files /dev/null and b/packages/uikit/assets/icons/png/ic-plus-outline-28@4x.png differ
diff --git a/packages/uikit/assets/icons/png/ic-purchases-28@4x.png b/packages/uikit/assets/icons/png/ic-purchases-28@4x.png
new file mode 100644
index 000000000..0b1477942
Binary files /dev/null and b/packages/uikit/assets/icons/png/ic-purchases-28@4x.png differ
diff --git a/packages/uikit/assets/icons/png/ic-qr-viewfinder-outline-28@4x.png b/packages/uikit/assets/icons/png/ic-qr-viewfinder-outline-28@4x.png
new file mode 100644
index 000000000..e95a577b8
Binary files /dev/null and b/packages/uikit/assets/icons/png/ic-qr-viewfinder-outline-28@4x.png differ
diff --git a/packages/uikit/assets/icons/png/ic-ruble-circle-32@4x.png b/packages/uikit/assets/icons/png/ic-ruble-circle-32@4x.png
new file mode 100644
index 000000000..469e248c1
Binary files /dev/null and b/packages/uikit/assets/icons/png/ic-ruble-circle-32@4x.png differ
diff --git a/packages/uikit/assets/icons/png/ic-snowflake-32@4x.png b/packages/uikit/assets/icons/png/ic-snowflake-32@4x.png
new file mode 100644
index 000000000..832e49102
Binary files /dev/null and b/packages/uikit/assets/icons/png/ic-snowflake-32@4x.png differ
diff --git a/packages/uikit/assets/icons/png/ic-sparkles-32@4x.png b/packages/uikit/assets/icons/png/ic-sparkles-32@4x.png
new file mode 100644
index 000000000..7a5dd0869
Binary files /dev/null and b/packages/uikit/assets/icons/png/ic-sparkles-32@4x.png differ
diff --git a/packages/uikit/assets/icons/png/ic-staking-outline-28@4x.png b/packages/uikit/assets/icons/png/ic-staking-outline-28@4x.png
new file mode 100644
index 000000000..a0fb8e115
Binary files /dev/null and b/packages/uikit/assets/icons/png/ic-staking-outline-28@4x.png differ
diff --git a/packages/uikit/assets/icons/png/ic-sterling-circle-32@4x.png b/packages/uikit/assets/icons/png/ic-sterling-circle-32@4x.png
new file mode 100644
index 000000000..ff361dace
Binary files /dev/null and b/packages/uikit/assets/icons/png/ic-sterling-circle-32@4x.png differ
diff --git a/packages/uikit/assets/icons/png/ic-sun-32@4x.png b/packages/uikit/assets/icons/png/ic-sun-32@4x.png
new file mode 100644
index 000000000..23f53d884
Binary files /dev/null and b/packages/uikit/assets/icons/png/ic-sun-32@4x.png differ
diff --git a/packages/uikit/assets/icons/png/ic-swap-horizontal-outline-28@4x.png b/packages/uikit/assets/icons/png/ic-swap-horizontal-outline-28@4x.png
new file mode 100644
index 000000000..226e72a5b
Binary files /dev/null and b/packages/uikit/assets/icons/png/ic-swap-horizontal-outline-28@4x.png differ
diff --git a/packages/uikit/assets/icons/png/ic-usd-outline-28@4x.png b/packages/uikit/assets/icons/png/ic-usd-outline-28@4x.png
new file mode 100644
index 000000000..f0776e296
Binary files /dev/null and b/packages/uikit/assets/icons/png/ic-usd-outline-28@4x.png differ
diff --git a/packages/uikit/assets/icons/png/ic-wallet-32@4x.png b/packages/uikit/assets/icons/png/ic-wallet-32@4x.png
new file mode 100644
index 000000000..8d0911dd1
Binary files /dev/null and b/packages/uikit/assets/icons/png/ic-wallet-32@4x.png differ
diff --git a/packages/uikit/assets/icons/svg/28/ic-arrow-down-outline-28.svg b/packages/uikit/assets/icons/svg/28/ic-arrow-down-outline-28.svg
new file mode 100644
index 000000000..b8a10d418
--- /dev/null
+++ b/packages/uikit/assets/icons/svg/28/ic-arrow-down-outline-28.svg
@@ -0,0 +1,3 @@
+
diff --git a/packages/uikit/assets/icons/svg/28/ic-arrow-right-outline-28.svg b/packages/uikit/assets/icons/svg/28/ic-arrow-right-outline-28.svg
new file mode 100644
index 000000000..3d2017794
--- /dev/null
+++ b/packages/uikit/assets/icons/svg/28/ic-arrow-right-outline-28.svg
@@ -0,0 +1,3 @@
+
diff --git a/packages/uikit/assets/icons/svg/28/ic-arrow-up-outline-28.svg b/packages/uikit/assets/icons/svg/28/ic-arrow-up-outline-28.svg
new file mode 100644
index 000000000..9722b012a
--- /dev/null
+++ b/packages/uikit/assets/icons/svg/28/ic-arrow-up-outline-28.svg
@@ -0,0 +1,3 @@
+
diff --git a/packages/uikit/assets/icons/svg/28/ic-gear-outline-28.svg b/packages/uikit/assets/icons/svg/28/ic-gear-outline-28.svg
new file mode 100644
index 000000000..e81d11166
--- /dev/null
+++ b/packages/uikit/assets/icons/svg/28/ic-gear-outline-28.svg
@@ -0,0 +1,8 @@
+
diff --git a/packages/uikit/assets/icons/svg/28/ic-minus-outline-28.svg b/packages/uikit/assets/icons/svg/28/ic-minus-outline-28.svg
new file mode 100644
index 000000000..c708c3597
--- /dev/null
+++ b/packages/uikit/assets/icons/svg/28/ic-minus-outline-28.svg
@@ -0,0 +1,3 @@
+
diff --git a/packages/uikit/assets/icons/svg/28/ic-plus-outline-28.svg b/packages/uikit/assets/icons/svg/28/ic-plus-outline-28.svg
new file mode 100644
index 000000000..d43e7fe08
--- /dev/null
+++ b/packages/uikit/assets/icons/svg/28/ic-plus-outline-28.svg
@@ -0,0 +1,3 @@
+
diff --git a/packages/uikit/assets/icons/svg/28/ic-purchases-28.svg b/packages/uikit/assets/icons/svg/28/ic-purchases-28.svg
new file mode 100644
index 000000000..d7d196367
--- /dev/null
+++ b/packages/uikit/assets/icons/svg/28/ic-purchases-28.svg
@@ -0,0 +1,4 @@
+
diff --git a/packages/uikit/assets/icons/svg/28/ic-qr-viewfinder-outline-28.svg b/packages/uikit/assets/icons/svg/28/ic-qr-viewfinder-outline-28.svg
new file mode 100644
index 000000000..376b31698
--- /dev/null
+++ b/packages/uikit/assets/icons/svg/28/ic-qr-viewfinder-outline-28.svg
@@ -0,0 +1,3 @@
+
diff --git a/packages/uikit/assets/icons/svg/28/ic-staking-outline-28.svg b/packages/uikit/assets/icons/svg/28/ic-staking-outline-28.svg
new file mode 100644
index 000000000..ff59f731e
--- /dev/null
+++ b/packages/uikit/assets/icons/svg/28/ic-staking-outline-28.svg
@@ -0,0 +1,3 @@
+
diff --git a/packages/uikit/assets/icons/svg/28/ic-swap-horizontal-outline-28.svg b/packages/uikit/assets/icons/svg/28/ic-swap-horizontal-outline-28.svg
new file mode 100644
index 000000000..1465563ce
--- /dev/null
+++ b/packages/uikit/assets/icons/svg/28/ic-swap-horizontal-outline-28.svg
@@ -0,0 +1,3 @@
+
diff --git a/packages/uikit/assets/icons/svg/28/ic-usd-outline-28.svg b/packages/uikit/assets/icons/svg/28/ic-usd-outline-28.svg
new file mode 100644
index 000000000..a0303fa0f
--- /dev/null
+++ b/packages/uikit/assets/icons/svg/28/ic-usd-outline-28.svg
@@ -0,0 +1,3 @@
+
diff --git a/packages/uikit/assets/icons/svg/32/ic-bank-card-32.svg b/packages/uikit/assets/icons/svg/32/ic-bank-card-32.svg
new file mode 100644
index 000000000..adc53095e
--- /dev/null
+++ b/packages/uikit/assets/icons/svg/32/ic-bank-card-32.svg
@@ -0,0 +1,3 @@
+
diff --git a/packages/uikit/assets/icons/svg/32/ic-chinese-yuan-circle-32.svg b/packages/uikit/assets/icons/svg/32/ic-chinese-yuan-circle-32.svg
new file mode 100644
index 000000000..51397c361
--- /dev/null
+++ b/packages/uikit/assets/icons/svg/32/ic-chinese-yuan-circle-32.svg
@@ -0,0 +1,3 @@
+
diff --git a/packages/uikit/assets/icons/svg/32/ic-dollar-circle-32.svg b/packages/uikit/assets/icons/svg/32/ic-dollar-circle-32.svg
new file mode 100644
index 000000000..e42e31bee
--- /dev/null
+++ b/packages/uikit/assets/icons/svg/32/ic-dollar-circle-32.svg
@@ -0,0 +1,3 @@
+
diff --git a/packages/uikit/assets/icons/svg/32/ic-euro-circle-32.svg b/packages/uikit/assets/icons/svg/32/ic-euro-circle-32.svg
new file mode 100644
index 000000000..2e0a625bf
--- /dev/null
+++ b/packages/uikit/assets/icons/svg/32/ic-euro-circle-32.svg
@@ -0,0 +1,3 @@
+
diff --git a/packages/uikit/assets/icons/svg/32/ic-flash-32.svg b/packages/uikit/assets/icons/svg/32/ic-flash-32.svg
new file mode 100644
index 000000000..b334b241a
--- /dev/null
+++ b/packages/uikit/assets/icons/svg/32/ic-flash-32.svg
@@ -0,0 +1,3 @@
+
diff --git a/packages/uikit/assets/icons/svg/32/ic-flash-circle-32.svg b/packages/uikit/assets/icons/svg/32/ic-flash-circle-32.svg
new file mode 100644
index 000000000..63528926a
--- /dev/null
+++ b/packages/uikit/assets/icons/svg/32/ic-flash-circle-32.svg
@@ -0,0 +1,3 @@
+
diff --git a/packages/uikit/assets/icons/svg/32/ic-gear-32.svg b/packages/uikit/assets/icons/svg/32/ic-gear-32.svg
new file mode 100644
index 000000000..196b06265
--- /dev/null
+++ b/packages/uikit/assets/icons/svg/32/ic-gear-32.svg
@@ -0,0 +1,3 @@
+
diff --git a/packages/uikit/assets/icons/svg/32/ic-hand-raised-32.svg b/packages/uikit/assets/icons/svg/32/ic-hand-raised-32.svg
new file mode 100644
index 000000000..273653964
--- /dev/null
+++ b/packages/uikit/assets/icons/svg/32/ic-hand-raised-32.svg
@@ -0,0 +1,3 @@
+
diff --git a/packages/uikit/assets/icons/svg/32/ic-hare-32.svg b/packages/uikit/assets/icons/svg/32/ic-hare-32.svg
new file mode 100644
index 000000000..c1678eaba
--- /dev/null
+++ b/packages/uikit/assets/icons/svg/32/ic-hare-32.svg
@@ -0,0 +1,3 @@
+
diff --git a/packages/uikit/assets/icons/svg/32/ic-inbox-32.svg b/packages/uikit/assets/icons/svg/32/ic-inbox-32.svg
new file mode 100644
index 000000000..efb37102d
--- /dev/null
+++ b/packages/uikit/assets/icons/svg/32/ic-inbox-32.svg
@@ -0,0 +1,3 @@
+
diff --git a/packages/uikit/assets/icons/svg/32/ic-indian-rupee-circle-32.svg b/packages/uikit/assets/icons/svg/32/ic-indian-rupee-circle-32.svg
new file mode 100644
index 000000000..42f974c72
--- /dev/null
+++ b/packages/uikit/assets/icons/svg/32/ic-indian-rupee-circle-32.svg
@@ -0,0 +1,3 @@
+
diff --git a/packages/uikit/assets/icons/svg/32/ic-key-32.svg b/packages/uikit/assets/icons/svg/32/ic-key-32.svg
new file mode 100644
index 000000000..90dc63826
--- /dev/null
+++ b/packages/uikit/assets/icons/svg/32/ic-key-32.svg
@@ -0,0 +1,3 @@
+
diff --git a/packages/uikit/assets/icons/svg/32/ic-leaf-32.svg b/packages/uikit/assets/icons/svg/32/ic-leaf-32.svg
new file mode 100644
index 000000000..26b8a22eb
--- /dev/null
+++ b/packages/uikit/assets/icons/svg/32/ic-leaf-32.svg
@@ -0,0 +1,3 @@
+
diff --git a/packages/uikit/assets/icons/svg/32/ic-lock-32.svg b/packages/uikit/assets/icons/svg/32/ic-lock-32.svg
new file mode 100644
index 000000000..e26c252d5
--- /dev/null
+++ b/packages/uikit/assets/icons/svg/32/ic-lock-32.svg
@@ -0,0 +1,3 @@
+
diff --git a/packages/uikit/assets/icons/svg/32/ic-magnifying-glass-circle-32.svg b/packages/uikit/assets/icons/svg/32/ic-magnifying-glass-circle-32.svg
new file mode 100644
index 000000000..3c8b3a237
--- /dev/null
+++ b/packages/uikit/assets/icons/svg/32/ic-magnifying-glass-circle-32.svg
@@ -0,0 +1,3 @@
+
diff --git a/packages/uikit/assets/icons/svg/32/ic-ruble-circle-32.svg b/packages/uikit/assets/icons/svg/32/ic-ruble-circle-32.svg
new file mode 100644
index 000000000..9a4a72023
--- /dev/null
+++ b/packages/uikit/assets/icons/svg/32/ic-ruble-circle-32.svg
@@ -0,0 +1,3 @@
+
diff --git a/packages/uikit/assets/icons/svg/32/ic-snowflake-32.svg b/packages/uikit/assets/icons/svg/32/ic-snowflake-32.svg
new file mode 100644
index 000000000..f8dde3cb4
--- /dev/null
+++ b/packages/uikit/assets/icons/svg/32/ic-snowflake-32.svg
@@ -0,0 +1,3 @@
+
diff --git a/packages/uikit/assets/icons/svg/32/ic-sparkles-32.svg b/packages/uikit/assets/icons/svg/32/ic-sparkles-32.svg
new file mode 100644
index 000000000..a5c8ce549
--- /dev/null
+++ b/packages/uikit/assets/icons/svg/32/ic-sparkles-32.svg
@@ -0,0 +1,3 @@
+
diff --git a/packages/uikit/assets/icons/svg/32/ic-sterling-circle-32.svg b/packages/uikit/assets/icons/svg/32/ic-sterling-circle-32.svg
new file mode 100644
index 000000000..577171262
--- /dev/null
+++ b/packages/uikit/assets/icons/svg/32/ic-sterling-circle-32.svg
@@ -0,0 +1,3 @@
+
diff --git a/packages/uikit/assets/icons/svg/32/ic-sun-32.svg b/packages/uikit/assets/icons/svg/32/ic-sun-32.svg
new file mode 100644
index 000000000..2ddc79b58
--- /dev/null
+++ b/packages/uikit/assets/icons/svg/32/ic-sun-32.svg
@@ -0,0 +1,3 @@
+
diff --git a/packages/uikit/assets/icons/svg/32/ic-wallet-32.svg b/packages/uikit/assets/icons/svg/32/ic-wallet-32.svg
new file mode 100644
index 000000000..34831ed60
--- /dev/null
+++ b/packages/uikit/assets/icons/svg/32/ic-wallet-32.svg
@@ -0,0 +1,3 @@
+
diff --git a/packages/uikit/src/components/ActionButton/ActionButton.tsx b/packages/uikit/src/components/ActionButton/ActionButton.tsx
new file mode 100644
index 000000000..2a7fcd304
--- /dev/null
+++ b/packages/uikit/src/components/ActionButton/ActionButton.tsx
@@ -0,0 +1,54 @@
+import React from 'react';
+import { Dimensions } from 'react-native';
+import { Steezy } from '../../styles';
+import { Text } from '../Text';
+import { TouchableOpacity } from '../TouchableOpacity';
+import { Icon, IconNames } from '../Icon';
+
+export interface ActionButtonProps {
+ title: string;
+ icon: IconNames;
+ onPress?: () => void;
+ disabled?: boolean;
+ inRow?: number;
+}
+
+const containerWidth = Dimensions.get('window').width - 32;
+export const ActionButton = ({
+ title,
+ icon,
+ onPress,
+ disabled,
+ inRow = 3,
+}: ActionButtonProps) => {
+ const width = containerWidth / inRow;
+ return (
+
+
+
+ {title}
+
+
+ );
+};
+
+const styles = Steezy.create({
+ actionButton: {
+ paddingVertical: 16,
+ alignItems: 'center',
+ justifyContent: 'center',
+ gap: 4,
+ },
+ actionButtonDisabled: {
+ opacity: 0.4,
+ },
+});
diff --git a/packages/uikit/src/components/ActionButton/Container.tsx b/packages/uikit/src/components/ActionButton/Container.tsx
new file mode 100644
index 000000000..3c2f904d4
--- /dev/null
+++ b/packages/uikit/src/components/ActionButton/Container.tsx
@@ -0,0 +1,36 @@
+import React, { memo, ReactNode } from 'react';
+import { Separators } from './Separators';
+import { View } from '../View';
+import { Steezy } from '../../styles';
+import { ActionButtonProps, ActionButton } from './ActionButton';
+
+export interface ActionButtonsContainerProps {
+ buttons: (ActionButtonProps & { id: string; visible?: boolean })[];
+}
+
+export const ActionButtons = memo((props) => {
+ const buttonsToBeRendered = props.buttons.filter(
+ (button) => button && (button.visible == null || button.visible),
+ );
+
+ return (
+
+
+ {buttonsToBeRendered.map((button, index) => (
+
+ ))}
+
+ );
+});
+
+const styles = Steezy.create({
+ container: {
+ flexDirection: 'row',
+ flexWrap: 'wrap',
+ paddingBottom: 19.5,
+ },
+});
diff --git a/packages/uikit/src/components/ActionButton/Separators.tsx b/packages/uikit/src/components/ActionButton/Separators.tsx
new file mode 100644
index 000000000..09717212f
--- /dev/null
+++ b/packages/uikit/src/components/ActionButton/Separators.tsx
@@ -0,0 +1,248 @@
+import Svg, { Defs, LinearGradient, Rect, Stop } from 'react-native-svg';
+import { Dimensions } from 'react-native';
+import React from 'react';
+import { DarkTheme } from '@tonkeeper/uikit/src/styles/themes/dark';
+import { Steezy } from '../../styles';
+import { View } from '../View';
+
+const svgWidth = Dimensions.get('window').width - 32;
+const lineWidth = svgWidth - 56 * 2;
+const verticalLinesXOffset = svgWidth / 3;
+
+export function Separators({ numOfActions }: { numOfActions?: number }) {
+ switch (numOfActions) {
+ case 1:
+ return null;
+ case 2:
+ return (
+
+
+
+ );
+ case 3:
+ return (
+
+
+
+ );
+ default:
+ return (
+
+
+
+ );
+ }
+}
+
+const getLinearGradientProps = (id) => {
+ switch (id) {
+ case 'gradientHorizontal':
+ return { x1: '1', y1: '0', x2: '0', y2: '0', gradientUnits: 'objectBoundingBox' };
+ case 'gradientHorizontalReversed':
+ return { x1: '0', x2: '1', gradientUnits: 'objectBoundingBox' };
+ case 'gradientVertical':
+ return { y1: '1', y2: '0', gradientUnits: 'objectBoundingBox' };
+ case 'gradientVerticalReversed':
+ return { y1: '0', y2: '1', gradientUnits: 'objectBoundingBox' };
+ default:
+ return {};
+ }
+};
+
+let stopPoints = [
+ 0, 0.0666667, 0.133333, 0.2, 0.266667, 0.333333, 0.4, 0.466667, 0.533333, 0.6, 0.666667,
+ 0.733333, 0.8, 0.866667, 0.933333, 1,
+];
+
+const stopPointsJSX = stopPoints.map((offset, index) => (
+
+));
+
+const Gradients = () => (
+
+ {[
+ 'gradientHorizontal',
+ 'gradientHorizontalReversed',
+ 'gradientVertical',
+ 'gradientVerticalReversed',
+ ].map((id) => (
+
+ {stopPointsJSX}
+
+ ))}
+
+);
+
+function SeparatorsTwoRows() {
+ return (
+
+ );
+}
+
+function SeparatorsTwoActions() {
+ return (
+
+ );
+}
+
+function SeparatorsOneRow() {
+ return (
+
+ );
+}
+
+const styles = Steezy.create({
+ separatorsContainerOneRow: {
+ position: 'absolute',
+ top: 12,
+ bottom: 12,
+ left: 0,
+ right: 0,
+ },
+ separatorsContainerTwoRows: {
+ position: 'absolute',
+ top: 24,
+ bottom: 24,
+ left: 0,
+ right: 0,
+ },
+});
diff --git a/packages/uikit/src/components/ActionButton/index.ts b/packages/uikit/src/components/ActionButton/index.ts
new file mode 100644
index 000000000..1537e7d7d
--- /dev/null
+++ b/packages/uikit/src/components/ActionButton/index.ts
@@ -0,0 +1,3 @@
+export * from './Separators';
+export * from './ActionButton';
+export * from './Container';
diff --git a/packages/uikit/src/components/Icon/Icon.types.ts b/packages/uikit/src/components/Icon/Icon.types.ts
index 214cc7aea..0d0e3bcb0 100644
--- a/packages/uikit/src/components/Icon/Icon.types.ts
+++ b/packages/uikit/src/components/Icon/Icon.types.ts
@@ -60,7 +60,10 @@ export type IconNames =
| 'ic-almost-empty-battery-28'
| 'ic-appearance-28'
| 'ic-arrow-down-28'
+ | 'ic-arrow-down-outline-28'
+ | 'ic-arrow-right-outline-28'
| 'ic-arrow-up-28'
+ | 'ic-arrow-up-outline-28'
| 'ic-battery-28'
| 'ic-bell-28'
| 'ic-creditcard-28'
@@ -81,6 +84,7 @@ export type IconNames =
| 'ic-flash-28'
| 'ic-full-battery-28'
| 'ic-gear-28'
+ | 'ic-gear-outline-28'
| 'ic-globe-28'
| 'ic-home-28'
| 'ic-jetton-28'
@@ -90,11 +94,15 @@ export type IconNames =
| 'ic-magnifying-glass-28'
| 'ic-message-bubble-28'
| 'ic-minus-28'
+ | 'ic-minus-outline-28'
| 'ic-money-28'
| 'ic-nft-collection-28'
| 'ic-notification-28'
| 'ic-plus-28'
| 'ic-plus-circle-28'
+ | 'ic-plus-outline-28'
+ | 'ic-purchases-28'
+ | 'ic-qr-viewfinder-outline-28'
| 'ic-reorder-28'
| 'ic-return-28'
| 'ic-secure-28'
@@ -103,11 +111,13 @@ export type IconNames =
| 'ic-shopping-bag-28'
| 'ic-speed-28'
| 'ic-staking-28'
+ | 'ic-staking-outline-28'
| 'ic-star-28'
| 'ic-success-28'
| 'ic-swap-28'
| 'ic-swap-horizontal-28'
| 'ic-swap-horizontal-alternative-28'
+ | 'ic-swap-horizontal-outline-28'
| 'ic-telegram-28'
| 'ic-testnet-28'
| 'ic-ticket-28'
@@ -117,13 +127,35 @@ export type IconNames =
| 'ic-tray-arrow-down-28'
| 'ic-tray-arrow-up-28'
| 'ic-usd-28'
+ | 'ic-usd-outline-28'
| 'ic-viewfinder-28'
| 'ic-wallet-28'
| 'ic-warning-28'
| 'ic-xmark-28'
| 'ic-xmark-outline-28'
+ | 'ic-bank-card-32'
| 'ic-checkmark-circle-32'
+ | 'ic-chinese-yuan-circle-32'
+ | 'ic-dollar-circle-32'
+ | 'ic-euro-circle-32'
| 'ic-exclamationmark-circle-32'
+ | 'ic-flash-32'
+ | 'ic-flash-circle-32'
+ | 'ic-gear-32'
+ | 'ic-hand-raised-32'
+ | 'ic-hare-32'
+ | 'ic-inbox-32'
+ | 'ic-indian-rupee-circle-32'
+ | 'ic-key-32'
+ | 'ic-leaf-32'
+ | 'ic-lock-32'
+ | 'ic-magnifying-glass-circle-32'
+ | 'ic-ruble-circle-32'
+ | 'ic-snowflake-32'
+ | 'ic-sparkles-32'
+ | 'ic-sterling-circle-32'
+ | 'ic-sun-32'
+ | 'ic-wallet-32'
| 'ic-almost-empty-battery-34'
| 'ic-empty-battery-accent-flash-34'
| 'ic-empty-battery-flash-34'
@@ -216,7 +248,10 @@ export const AllIcons = [
'ic-almost-empty-battery-28',
'ic-appearance-28',
'ic-arrow-down-28',
+ 'ic-arrow-down-outline-28',
+ 'ic-arrow-right-outline-28',
'ic-arrow-up-28',
+ 'ic-arrow-up-outline-28',
'ic-battery-28',
'ic-bell-28',
'ic-creditcard-28',
@@ -237,6 +272,7 @@ export const AllIcons = [
'ic-flash-28',
'ic-full-battery-28',
'ic-gear-28',
+ 'ic-gear-outline-28',
'ic-globe-28',
'ic-home-28',
'ic-jetton-28',
@@ -246,11 +282,15 @@ export const AllIcons = [
'ic-magnifying-glass-28',
'ic-message-bubble-28',
'ic-minus-28',
+ 'ic-minus-outline-28',
'ic-money-28',
'ic-nft-collection-28',
'ic-notification-28',
'ic-plus-28',
'ic-plus-circle-28',
+ 'ic-plus-outline-28',
+ 'ic-purchases-28',
+ 'ic-qr-viewfinder-outline-28',
'ic-reorder-28',
'ic-return-28',
'ic-secure-28',
@@ -259,11 +299,13 @@ export const AllIcons = [
'ic-shopping-bag-28',
'ic-speed-28',
'ic-staking-28',
+ 'ic-staking-outline-28',
'ic-star-28',
'ic-success-28',
'ic-swap-28',
'ic-swap-horizontal-28',
'ic-swap-horizontal-alternative-28',
+ 'ic-swap-horizontal-outline-28',
'ic-telegram-28',
'ic-testnet-28',
'ic-ticket-28',
@@ -273,13 +315,35 @@ export const AllIcons = [
'ic-tray-arrow-down-28',
'ic-tray-arrow-up-28',
'ic-usd-28',
+ 'ic-usd-outline-28',
'ic-viewfinder-28',
'ic-wallet-28',
'ic-warning-28',
'ic-xmark-28',
'ic-xmark-outline-28',
+ 'ic-bank-card-32',
'ic-checkmark-circle-32',
+ 'ic-chinese-yuan-circle-32',
+ 'ic-dollar-circle-32',
+ 'ic-euro-circle-32',
'ic-exclamationmark-circle-32',
+ 'ic-flash-32',
+ 'ic-flash-circle-32',
+ 'ic-gear-32',
+ 'ic-hand-raised-32',
+ 'ic-hare-32',
+ 'ic-inbox-32',
+ 'ic-indian-rupee-circle-32',
+ 'ic-key-32',
+ 'ic-leaf-32',
+ 'ic-lock-32',
+ 'ic-magnifying-glass-circle-32',
+ 'ic-ruble-circle-32',
+ 'ic-snowflake-32',
+ 'ic-sparkles-32',
+ 'ic-sterling-circle-32',
+ 'ic-sun-32',
+ 'ic-wallet-32',
'ic-almost-empty-battery-34',
'ic-empty-battery-accent-flash-34',
'ic-empty-battery-flash-34',
@@ -373,7 +437,10 @@ export const IconSizes = {
'ic-almost-empty-battery-28': 28,
'ic-appearance-28': 28,
'ic-arrow-down-28': 28,
+ 'ic-arrow-down-outline-28': 28,
+ 'ic-arrow-right-outline-28': 28,
'ic-arrow-up-28': 28,
+ 'ic-arrow-up-outline-28': 28,
'ic-battery-28': 28,
'ic-bell-28': 28,
'ic-creditcard-28': 28,
@@ -394,6 +461,7 @@ export const IconSizes = {
'ic-flash-28': 28,
'ic-full-battery-28': 28,
'ic-gear-28': 28,
+ 'ic-gear-outline-28': 28,
'ic-globe-28': 28,
'ic-home-28': 28,
'ic-jetton-28': 28,
@@ -403,11 +471,15 @@ export const IconSizes = {
'ic-magnifying-glass-28': 28,
'ic-message-bubble-28': 28,
'ic-minus-28': 28,
+ 'ic-minus-outline-28': 28,
'ic-money-28': 28,
'ic-nft-collection-28': 28,
'ic-notification-28': 28,
'ic-plus-28': 28,
'ic-plus-circle-28': 28,
+ 'ic-plus-outline-28': 28,
+ 'ic-purchases-28': 28,
+ 'ic-qr-viewfinder-outline-28': 28,
'ic-reorder-28': 28,
'ic-return-28': 28,
'ic-secure-28': 28,
@@ -416,11 +488,13 @@ export const IconSizes = {
'ic-shopping-bag-28': 28,
'ic-speed-28': 28,
'ic-staking-28': 28,
+ 'ic-staking-outline-28': 28,
'ic-star-28': 28,
'ic-success-28': 28,
'ic-swap-28': 28,
'ic-swap-horizontal-28': 28,
'ic-swap-horizontal-alternative-28': 28,
+ 'ic-swap-horizontal-outline-28': 28,
'ic-telegram-28': 28,
'ic-testnet-28': 28,
'ic-ticket-28': 28,
@@ -430,13 +504,35 @@ export const IconSizes = {
'ic-tray-arrow-down-28': 28,
'ic-tray-arrow-up-28': 28,
'ic-usd-28': 28,
+ 'ic-usd-outline-28': 28,
'ic-viewfinder-28': 28,
'ic-wallet-28': 28,
'ic-warning-28': 28,
'ic-xmark-28': 28,
'ic-xmark-outline-28': 28,
+ 'ic-bank-card-32': 32,
'ic-checkmark-circle-32': 32,
+ 'ic-chinese-yuan-circle-32': 32,
+ 'ic-dollar-circle-32': 32,
+ 'ic-euro-circle-32': 32,
'ic-exclamationmark-circle-32': 32,
+ 'ic-flash-32': 32,
+ 'ic-flash-circle-32': 32,
+ 'ic-gear-32': 32,
+ 'ic-hand-raised-32': 32,
+ 'ic-hare-32': 32,
+ 'ic-inbox-32': 32,
+ 'ic-indian-rupee-circle-32': 32,
+ 'ic-key-32': 32,
+ 'ic-leaf-32': 32,
+ 'ic-lock-32': 32,
+ 'ic-magnifying-glass-circle-32': 32,
+ 'ic-ruble-circle-32': 32,
+ 'ic-snowflake-32': 32,
+ 'ic-sparkles-32': 32,
+ 'ic-sterling-circle-32': 32,
+ 'ic-sun-32': 32,
+ 'ic-wallet-32': 32,
'ic-almost-empty-battery-34': 34,
'ic-empty-battery-accent-flash-34': 34,
'ic-empty-battery-flash-34': 34,
diff --git a/packages/uikit/src/components/Icon/IconList.native.ts b/packages/uikit/src/components/Icon/IconList.native.ts
index e6219fc78..84e50d81d 100644
--- a/packages/uikit/src/components/Icon/IconList.native.ts
+++ b/packages/uikit/src/components/Icon/IconList.native.ts
@@ -60,7 +60,10 @@ export const IconList = {
'ic-almost-empty-battery-28': require('../../../assets/icons/png/ic-almost-empty-battery-28.png'),
'ic-appearance-28': require('../../../assets/icons/png/ic-appearance-28.png'),
'ic-arrow-down-28': require('../../../assets/icons/png/ic-arrow-down-28.png'),
+ 'ic-arrow-down-outline-28': require('../../../assets/icons/png/ic-arrow-down-outline-28.png'),
+ 'ic-arrow-right-outline-28': require('../../../assets/icons/png/ic-arrow-right-outline-28.png'),
'ic-arrow-up-28': require('../../../assets/icons/png/ic-arrow-up-28.png'),
+ 'ic-arrow-up-outline-28': require('../../../assets/icons/png/ic-arrow-up-outline-28.png'),
'ic-battery-28': require('../../../assets/icons/png/ic-battery-28.png'),
'ic-bell-28': require('../../../assets/icons/png/ic-bell-28.png'),
'ic-creditcard-28': require('../../../assets/icons/png/ic-creditcard-28.png'),
@@ -81,6 +84,7 @@ export const IconList = {
'ic-flash-28': require('../../../assets/icons/png/ic-flash-28.png'),
'ic-full-battery-28': require('../../../assets/icons/png/ic-full-battery-28.png'),
'ic-gear-28': require('../../../assets/icons/png/ic-gear-28.png'),
+ 'ic-gear-outline-28': require('../../../assets/icons/png/ic-gear-outline-28.png'),
'ic-globe-28': require('../../../assets/icons/png/ic-globe-28.png'),
'ic-home-28': require('../../../assets/icons/png/ic-home-28.png'),
'ic-jetton-28': require('../../../assets/icons/png/ic-jetton-28.png'),
@@ -90,11 +94,15 @@ export const IconList = {
'ic-magnifying-glass-28': require('../../../assets/icons/png/ic-magnifying-glass-28.png'),
'ic-message-bubble-28': require('../../../assets/icons/png/ic-message-bubble-28.png'),
'ic-minus-28': require('../../../assets/icons/png/ic-minus-28.png'),
+ 'ic-minus-outline-28': require('../../../assets/icons/png/ic-minus-outline-28.png'),
'ic-money-28': require('../../../assets/icons/png/ic-money-28.png'),
'ic-nft-collection-28': require('../../../assets/icons/png/ic-nft-collection-28.png'),
'ic-notification-28': require('../../../assets/icons/png/ic-notification-28.png'),
'ic-plus-28': require('../../../assets/icons/png/ic-plus-28.png'),
'ic-plus-circle-28': require('../../../assets/icons/png/ic-plus-circle-28.png'),
+ 'ic-plus-outline-28': require('../../../assets/icons/png/ic-plus-outline-28.png'),
+ 'ic-purchases-28': require('../../../assets/icons/png/ic-purchases-28.png'),
+ 'ic-qr-viewfinder-outline-28': require('../../../assets/icons/png/ic-qr-viewfinder-outline-28.png'),
'ic-reorder-28': require('../../../assets/icons/png/ic-reorder-28.png'),
'ic-return-28': require('../../../assets/icons/png/ic-return-28.png'),
'ic-secure-28': require('../../../assets/icons/png/ic-secure-28.png'),
@@ -103,11 +111,13 @@ export const IconList = {
'ic-shopping-bag-28': require('../../../assets/icons/png/ic-shopping-bag-28.png'),
'ic-speed-28': require('../../../assets/icons/png/ic-speed-28.png'),
'ic-staking-28': require('../../../assets/icons/png/ic-staking-28.png'),
+ 'ic-staking-outline-28': require('../../../assets/icons/png/ic-staking-outline-28.png'),
'ic-star-28': require('../../../assets/icons/png/ic-star-28.png'),
'ic-success-28': require('../../../assets/icons/png/ic-success-28.png'),
'ic-swap-28': require('../../../assets/icons/png/ic-swap-28.png'),
'ic-swap-horizontal-28': require('../../../assets/icons/png/ic-swap-horizontal-28.png'),
'ic-swap-horizontal-alternative-28': require('../../../assets/icons/png/ic-swap-horizontal-alternative-28.png'),
+ 'ic-swap-horizontal-outline-28': require('../../../assets/icons/png/ic-swap-horizontal-outline-28.png'),
'ic-telegram-28': require('../../../assets/icons/png/ic-telegram-28.png'),
'ic-testnet-28': require('../../../assets/icons/png/ic-testnet-28.png'),
'ic-ticket-28': require('../../../assets/icons/png/ic-ticket-28.png'),
@@ -117,13 +127,35 @@ export const IconList = {
'ic-tray-arrow-down-28': require('../../../assets/icons/png/ic-tray-arrow-down-28.png'),
'ic-tray-arrow-up-28': require('../../../assets/icons/png/ic-tray-arrow-up-28.png'),
'ic-usd-28': require('../../../assets/icons/png/ic-usd-28.png'),
+ 'ic-usd-outline-28': require('../../../assets/icons/png/ic-usd-outline-28.png'),
'ic-viewfinder-28': require('../../../assets/icons/png/ic-viewfinder-28.png'),
'ic-wallet-28': require('../../../assets/icons/png/ic-wallet-28.png'),
'ic-warning-28': require('../../../assets/icons/png/ic-warning-28.png'),
'ic-xmark-28': require('../../../assets/icons/png/ic-xmark-28.png'),
'ic-xmark-outline-28': require('../../../assets/icons/png/ic-xmark-outline-28.png'),
+ 'ic-bank-card-32': require('../../../assets/icons/png/ic-bank-card-32.png'),
'ic-checkmark-circle-32': require('../../../assets/icons/png/ic-checkmark-circle-32.png'),
+ 'ic-chinese-yuan-circle-32': require('../../../assets/icons/png/ic-chinese-yuan-circle-32.png'),
+ 'ic-dollar-circle-32': require('../../../assets/icons/png/ic-dollar-circle-32.png'),
+ 'ic-euro-circle-32': require('../../../assets/icons/png/ic-euro-circle-32.png'),
'ic-exclamationmark-circle-32': require('../../../assets/icons/png/ic-exclamationmark-circle-32.png'),
+ 'ic-flash-32': require('../../../assets/icons/png/ic-flash-32.png'),
+ 'ic-flash-circle-32': require('../../../assets/icons/png/ic-flash-circle-32.png'),
+ 'ic-gear-32': require('../../../assets/icons/png/ic-gear-32.png'),
+ 'ic-hand-raised-32': require('../../../assets/icons/png/ic-hand-raised-32.png'),
+ 'ic-hare-32': require('../../../assets/icons/png/ic-hare-32.png'),
+ 'ic-inbox-32': require('../../../assets/icons/png/ic-inbox-32.png'),
+ 'ic-indian-rupee-circle-32': require('../../../assets/icons/png/ic-indian-rupee-circle-32.png'),
+ 'ic-key-32': require('../../../assets/icons/png/ic-key-32.png'),
+ 'ic-leaf-32': require('../../../assets/icons/png/ic-leaf-32.png'),
+ 'ic-lock-32': require('../../../assets/icons/png/ic-lock-32.png'),
+ 'ic-magnifying-glass-circle-32': require('../../../assets/icons/png/ic-magnifying-glass-circle-32.png'),
+ 'ic-ruble-circle-32': require('../../../assets/icons/png/ic-ruble-circle-32.png'),
+ 'ic-snowflake-32': require('../../../assets/icons/png/ic-snowflake-32.png'),
+ 'ic-sparkles-32': require('../../../assets/icons/png/ic-sparkles-32.png'),
+ 'ic-sterling-circle-32': require('../../../assets/icons/png/ic-sterling-circle-32.png'),
+ 'ic-sun-32': require('../../../assets/icons/png/ic-sun-32.png'),
+ 'ic-wallet-32': require('../../../assets/icons/png/ic-wallet-32.png'),
'ic-almost-empty-battery-34': require('../../../assets/icons/png/ic-almost-empty-battery-34.png'),
'ic-empty-battery-accent-flash-34': require('../../../assets/icons/png/ic-empty-battery-accent-flash-34.png'),
'ic-empty-battery-flash-34': require('../../../assets/icons/png/ic-empty-battery-flash-34.png'),
diff --git a/packages/uikit/src/components/List/ListItem.tsx b/packages/uikit/src/components/List/ListItem.tsx
index 5ffa5d09a..e1bba6905 100644
--- a/packages/uikit/src/components/List/ListItem.tsx
+++ b/packages/uikit/src/components/List/ListItem.tsx
@@ -119,6 +119,7 @@ export const ListItem = memo((props) => {
{isString(props.title) ? (
((props) => {
? 'label1'
: 'body1'
}
+ color={titleType === 'primary' ? 'textPrimary' : 'textSecondary'}
numberOfLines={titleNumberOfLines}
ellipsizeMode="tail"
>
diff --git a/packages/uikit/src/components/SlideButton/SlideButton.tsx b/packages/uikit/src/components/SlideButton/SlideButton.tsx
new file mode 100644
index 000000000..558fed383
--- /dev/null
+++ b/packages/uikit/src/components/SlideButton/SlideButton.tsx
@@ -0,0 +1,112 @@
+import React, { memo } from 'react';
+import { View } from '../View';
+import { Steezy } from '../../styles';
+import { Icon } from '../Icon';
+import { Text } from '../Text';
+import { GestureDetector, Gesture } from 'react-native-gesture-handler';
+import Animated, {
+ clamp,
+ ReduceMotion,
+ runOnJS,
+ useAnimatedStyle,
+ useSharedValue,
+ withDelay,
+ withSpring,
+ withTiming,
+} from 'react-native-reanimated';
+import {
+ triggerImpactLight,
+ triggerImpactMedium,
+ triggerNotificationSuccess,
+} from '@tonkeeper/mobile/src/utils';
+
+export interface SlideButtonProps {
+ onSuccessSlide: () => void;
+ text: string;
+}
+
+const BUTTON_WIDTH = 76;
+
+const SPRING_CONFIG = {
+ mass: 1.5,
+ damping: 90,
+ stiffness: 300,
+ overshootClamping: false,
+ reduceMotion: ReduceMotion.Never,
+};
+
+export const SlideButton = memo((props) => {
+ const buttonStyle = Steezy.useStyle(styles.button);
+ const leftOffset = useSharedValue(0);
+ const maxOffset = useSharedValue(0);
+
+ const panGesture = Gesture.Pan()
+ .onStart(() => {
+ runOnJS(triggerImpactMedium)();
+ })
+ .onUpdate((e) => {
+ leftOffset.value = e.translationX;
+ })
+ .onEnd((e) => {
+ if (e.translationX > maxOffset.value - BUTTON_WIDTH) {
+ runOnJS(triggerNotificationSuccess)();
+ leftOffset.value = withDelay(500, withSpring(0, SPRING_CONFIG));
+ return runOnJS(props.onSuccessSlide)();
+ }
+ runOnJS(triggerImpactLight)();
+ leftOffset.value = withSpring(0, SPRING_CONFIG);
+ });
+
+ const animatedButtonOffset = useAnimatedStyle(() => {
+ return {
+ transform: [
+ { translateX: clamp(leftOffset.value, 0, maxOffset.value - BUTTON_WIDTH) },
+ ],
+ };
+ });
+
+ const textContainerStyle = useAnimatedStyle(() => {
+ return {
+ opacity: withTiming(leftOffset.value ? 0 : 1, { duration: 175 }),
+ };
+ });
+
+ return (
+ (maxOffset.value = e.nativeEvent.layout.width)}
+ style={styles.container}
+ >
+
+
+ {props.text}
+
+
+
+
+
+
+
+
+ );
+});
+
+const styles = Steezy.create(({ colors }) => ({
+ button: {
+ position: 'absolute',
+ left: 0,
+ bottom: 0,
+ top: 0,
+ width: BUTTON_WIDTH,
+ backgroundColor: colors.accentBlue,
+ borderRadius: 16,
+ alignItems: 'center',
+ justifyContent: 'center',
+ },
+ container: {
+ height: 56,
+ backgroundColor: colors.backgroundContent,
+ borderRadius: 16,
+ alignItems: 'center',
+ justifyContent: 'center',
+ },
+}));
diff --git a/packages/uikit/src/components/SlideButton/index.ts b/packages/uikit/src/components/SlideButton/index.ts
new file mode 100644
index 000000000..bf2be2a48
--- /dev/null
+++ b/packages/uikit/src/components/SlideButton/index.ts
@@ -0,0 +1 @@
+export * from './SlideButton';
diff --git a/packages/uikit/src/components/TonIcon.tsx b/packages/uikit/src/components/TonIcon.tsx
index 04454c00d..876f5a2ea 100644
--- a/packages/uikit/src/components/TonIcon.tsx
+++ b/packages/uikit/src/components/TonIcon.tsx
@@ -56,7 +56,11 @@ export const TonIcon = memo((props) => {
return (
{showDiamond && hasDiamond ? (
-
+
) : (
)}
diff --git a/packages/uikit/src/components/WalletIcon.tsx b/packages/uikit/src/components/WalletIcon.tsx
new file mode 100644
index 000000000..95bc13ec2
--- /dev/null
+++ b/packages/uikit/src/components/WalletIcon.tsx
@@ -0,0 +1,18 @@
+import { memo } from 'react';
+import { StyleProp, Text, TextStyle } from 'react-native';
+import { WALLET_ICONS } from '../utils/walletIcons';
+import { Icon, IconNames } from './Icon';
+
+interface WalletIconProps {
+ value: string;
+ emojiStyle?: StyleProp;
+ size?: number;
+}
+
+export const WalletIcon = memo((props) => {
+ if (WALLET_ICONS.includes(props.value)) {
+ return ;
+ }
+
+ return {props.value};
+});
diff --git a/packages/uikit/src/containers/Screen/ScreenFlashList.tsx b/packages/uikit/src/containers/Screen/ScreenFlashList.tsx
index 33d6046f1..11d770d16 100644
--- a/packages/uikit/src/containers/Screen/ScreenFlashList.tsx
+++ b/packages/uikit/src/containers/Screen/ScreenFlashList.tsx
@@ -1,4 +1,3 @@
-import { FlashList, ContentStyle, FlashListProps } from '@shopify/flash-list';
import { Fragment, forwardRef, memo, useEffect, useMemo } from 'react';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { ScreenBottomSeparator } from './ScreenBottomSeparator';
@@ -46,18 +45,22 @@ export const ScreenScrollList = memo(
// useScrollHandler(undefined, true); // TODO: remove this, when old separator will be removed
- const contentStyle: ContentStyle = useMemo(
- () => ({
- paddingBottom: safeArea ? safeAreaInsets.bottom : tabBarHeight,
- ...contentContainerStyle,
- }),
+ const contentStyle = useMemo(
+ () => [
+ {
+ paddingBottom: safeArea ? safeAreaInsets.bottom : tabBarHeight + 16,
+ },
+ contentContainerStyle,
+ ],
[contentContainerStyle, tabBarHeight, safeArea, safeAreaInsets.bottom],
);
const HeaderComponent = (
- {typeof ListHeaderComponent === 'function' ? ListHeaderComponent() : ListHeaderComponent as any}
+ {typeof ListHeaderComponent === 'function'
+ ? ListHeaderComponent()
+ : (ListHeaderComponent as any)}
);
diff --git a/packages/uikit/src/containers/Screen/ScreenHeader.tsx b/packages/uikit/src/containers/Screen/ScreenHeader.tsx
index 77907e34b..1a180b080 100644
--- a/packages/uikit/src/containers/Screen/ScreenHeader.tsx
+++ b/packages/uikit/src/containers/Screen/ScreenHeader.tsx
@@ -122,7 +122,7 @@ export const ScreenHeader = memo((props) => {
return {};
});
- const isSmallTitle = typeof title === 'string' && title.length > 18;
+ const isSmallTitle = typeof title === 'string' && title.length <= 18;
const backButtonSlot = (