mirror of
https://github.com/BlueWallet/BlueWallet.git
synced 2024-11-19 09:50:15 +01:00
Merge branch 'master' into devmenu
This commit is contained in:
commit
f5c4f934cc
4
Gemfile
4
Gemfile
@ -3,6 +3,6 @@ source "https://rubygems.org"
|
||||
# You may use http://rbenv.org/ or https://rvm.io/ to install and use this version
|
||||
ruby "3.1.6"
|
||||
gem 'rubyzip', '2.3.2'
|
||||
gem "cocoapods", "1.15.2"
|
||||
gem "activesupport", ">= 6.1.7.3", "< 7.2.1"
|
||||
gem 'cocoapods', '>= 1.13', '!= 1.15.0', '!= 1.15.1'
|
||||
gem 'activesupport', '>= 6.1.7.5', '!= 7.1.0'
|
||||
gem "fastlane"
|
16
Gemfile.lock
16
Gemfile.lock
@ -5,7 +5,7 @@ GEM
|
||||
base64
|
||||
nkf
|
||||
rexml
|
||||
activesupport (7.2.0)
|
||||
activesupport (7.2.1)
|
||||
base64
|
||||
bigdecimal
|
||||
concurrent-ruby (~> 1.0, >= 1.3.1)
|
||||
@ -24,8 +24,8 @@ GEM
|
||||
artifactory (3.0.17)
|
||||
atomos (0.1.3)
|
||||
aws-eventstream (1.3.0)
|
||||
aws-partitions (1.965.0)
|
||||
aws-sdk-core (3.201.5)
|
||||
aws-partitions (1.970.0)
|
||||
aws-sdk-core (3.202.2)
|
||||
aws-eventstream (~> 1, >= 1.3.0)
|
||||
aws-partitions (~> 1, >= 1.651.0)
|
||||
aws-sigv4 (~> 1.9)
|
||||
@ -33,7 +33,7 @@ GEM
|
||||
aws-sdk-kms (1.88.0)
|
||||
aws-sdk-core (~> 3, >= 3.201.0)
|
||||
aws-sigv4 (~> 1.5)
|
||||
aws-sdk-s3 (1.158.0)
|
||||
aws-sdk-s3 (1.159.0)
|
||||
aws-sdk-core (~> 3, >= 3.201.0)
|
||||
aws-sdk-kms (~> 1)
|
||||
aws-sigv4 (~> 1.5)
|
||||
@ -217,7 +217,7 @@ GEM
|
||||
json (2.7.2)
|
||||
jwt (2.8.2)
|
||||
base64
|
||||
logger (1.6.0)
|
||||
logger (1.6.1)
|
||||
mini_magick (4.13.2)
|
||||
mini_mime (1.1.5)
|
||||
minitest (5.25.1)
|
||||
@ -239,7 +239,7 @@ GEM
|
||||
trailblazer-option (>= 0.1.1, < 0.2.0)
|
||||
uber (< 0.2.0)
|
||||
retriable (3.1.2)
|
||||
rexml (3.3.5)
|
||||
rexml (3.3.6)
|
||||
strscan
|
||||
rouge (2.0.7)
|
||||
ruby-macho (2.5.1)
|
||||
@ -287,8 +287,8 @@ PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
activesupport (>= 6.1.7.3, < 7.2.1)
|
||||
cocoapods (= 1.15.2)
|
||||
activesupport (>= 6.1.7.5, != 7.1.0)
|
||||
cocoapods (>= 1.13, != 1.15.1, != 1.15.0)
|
||||
fastlane
|
||||
rubyzip (= 2.3.2)
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
apply plugin: "com.android.application"
|
||||
apply plugin: "com.facebook.react"
|
||||
apply plugin: "org.jetbrains.kotlin.android"
|
||||
apply plugin: "com.facebook.react"
|
||||
|
||||
/**
|
||||
* This is the configuration block to customize your React Native Android app.
|
||||
@ -8,14 +8,14 @@ apply plugin: "org.jetbrains.kotlin.android"
|
||||
*/
|
||||
react {
|
||||
/* Folders */
|
||||
// The root of your project, i.e. where "package.json" lives. Default is '..'
|
||||
// root = file("../")
|
||||
// The folder where the react-native NPM package is. Default is ../node_modules/react-native
|
||||
// reactNativeDir = file("../node_modules/react-native")
|
||||
// The folder where the react-native Codegen package is. Default is ../node_modules/@react-native/codegen
|
||||
// codegenDir = file("../node_modules/@react-native/codegen")
|
||||
// The cli.js file which is the React Native CLI entrypoint. Default is ../node_modules/react-native/cli.js
|
||||
// cliFile = file("../node_modules/react-native/cli.js")
|
||||
// The root of your project, i.e. where "package.json" lives. Default is '../..'
|
||||
// root = file("../../")
|
||||
// The folder where the react-native NPM package is. Default is ../../node_modules/react-native
|
||||
// reactNativeDir = file("../../node_modules/react-native")
|
||||
// The folder where the react-native Codegen package is. Default is ../../node_modules/@react-native/codegen
|
||||
// codegenDir = file("../../node_modules/@react-native/codegen")
|
||||
// The cli.js file which is the React Native CLI entrypoint. Default is ../../node_modules/react-native/cli.js
|
||||
// cliFile = file("../../node_modules/react-native/cli.js")
|
||||
|
||||
/* Variants */
|
||||
// The list of variants to that are debuggable. For those we're going to
|
||||
@ -49,6 +49,9 @@ react {
|
||||
//
|
||||
// The list of flags to pass to the Hermes compiler. By default is "-O", "-output-source-map"
|
||||
// hermesFlags = ["-O", "-output-source-map"]
|
||||
|
||||
/* Autolinking */
|
||||
autolinkLibrariesWithApp()
|
||||
}
|
||||
|
||||
/**
|
||||
@ -80,7 +83,7 @@ android {
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
versionCode 1
|
||||
versionName "7.0.3"
|
||||
versionName "7.0.4"
|
||||
testBuildType System.getProperty('testBuildType', 'debug')
|
||||
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
|
||||
}
|
||||
@ -116,9 +119,10 @@ task copyFiatUnits(type: Copy) {
|
||||
preBuild.dependsOn(copyFiatUnits)
|
||||
|
||||
dependencies {
|
||||
androidTestImplementation('com.wix:detox:+')
|
||||
// The version of react-native is set by the React Native Gradle Plugin
|
||||
implementation("com.facebook.react:react-android")
|
||||
implementation 'androidx.core:core-ktx'
|
||||
implementation 'androidx.core:core-ktx:1.13.1'
|
||||
implementation 'androidx.work:work-runtime-ktx:2.9.1'
|
||||
|
||||
if (hermesEnabled.toBoolean()) {
|
||||
@ -126,13 +130,10 @@ dependencies {
|
||||
} else {
|
||||
implementation jscFlavor
|
||||
}
|
||||
androidTestImplementation('com.wix:detox:+')
|
||||
implementation 'androidx.appcompat:appcompat:1.6.1'
|
||||
androidTestImplementation('com.wix:detox:0.1.1')
|
||||
implementation 'androidx.appcompat:appcompat:1.7.0'
|
||||
implementation fileTree(dir: "libs", include: ["*.jar"])
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
|
||||
}
|
||||
apply plugin: 'com.google.gms.google-services' // Google Services plugin
|
||||
|
||||
apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle")
|
||||
apply plugin: 'org.jetbrains.kotlin.android'; applyNativeModulesAppBuildGradle(project)
|
||||
apply plugin: "com.bugsnag.android.gradle"
|
3
android/app/proguard-rules.pro
vendored
3
android/app/proguard-rules.pro
vendored
@ -11,8 +11,5 @@
|
||||
|
||||
-keep class com.facebook.hermes.unicode.** { *; }
|
||||
-keep class com.facebook.jni.** { *; }
|
||||
-keep class com.sifir.** { *;}
|
||||
-keep interface com.sifir.** { *;}
|
||||
-keep enum com.sifir.** { *;}
|
||||
-keep class com.swmansion.reanimated.** { *; }
|
||||
-keep class com.facebook.react.turbomodule.** { *; }
|
||||
|
@ -23,7 +23,7 @@ buildscript {
|
||||
classpath("com.facebook.react:react-native-gradle-plugin")
|
||||
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version")
|
||||
classpath 'com.google.gms:google-services:4.4.2' // Google Services plugin
|
||||
classpath("com.bugsnag:bugsnag-android-gradle-plugin:8.+")
|
||||
classpath("com.bugsnag:bugsnag-android-gradle-plugin:8.1.0")
|
||||
}
|
||||
}
|
||||
|
||||
@ -52,11 +52,6 @@ allprojects {
|
||||
google()
|
||||
maven { url 'https://www.jitpack.io' }
|
||||
}
|
||||
configurations.all {
|
||||
resolutionStrategy {
|
||||
force 'androidx.activity:activity:1.5.1'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
subprojects {
|
||||
|
@ -21,9 +21,7 @@ org.gradle.jvmargs=-Xmx4096m -XX:MaxMetaspaceSize=1024m
|
||||
# Android operating system, and which are packaged with your app's APK
|
||||
# https://developer.android.com/topic/libraries/support-library/androidx-rn
|
||||
android.useAndroidX=true
|
||||
# Automatically convert third-party libraries to use AndroidX
|
||||
android.enableJetifier=true
|
||||
|
||||
# Use this property to specify which architecture you want to build.
|
||||
# You can also override it from the CLI using
|
||||
# ./gradlew <task> -PreactNativeArchitectures=x86_64
|
||||
|
@ -1,5 +1,7 @@
|
||||
pluginManagement { includeBuild("../node_modules/@react-native/gradle-plugin") }
|
||||
plugins { id("com.facebook.react.settings") }
|
||||
extensions.configure(com.facebook.react.ReactSettingsExtension){ ex -> ex.autolinkLibrariesFromCommand() }
|
||||
rootProject.name = 'BlueWallet'
|
||||
apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings)
|
||||
include ':app'
|
||||
includeBuild('../node_modules/@react-native/gradle-plugin')
|
||||
include ':detox'
|
||||
|
@ -36,7 +36,7 @@ export class LightningCustodianWallet extends LegacyWallet {
|
||||
* @param URI
|
||||
*/
|
||||
setBaseURI(URI: string | undefined) {
|
||||
this.baseURI = URI;
|
||||
this.baseURI = URI?.endsWith('/') ? URI.slice(0, -1) : URI;
|
||||
}
|
||||
|
||||
getBaseURI() {
|
||||
@ -579,7 +579,7 @@ export class LightningCustodianWallet extends LegacyWallet {
|
||||
}
|
||||
|
||||
static async isValidNodeAddress(address: string) {
|
||||
const response = await fetch(address + '/getinfo', {
|
||||
const response = await fetch((address?.endsWith('/') ? address.slice(0, -1) : address) + '/getinfo', {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
|
@ -1,11 +1,10 @@
|
||||
import React, { forwardRef } from 'react';
|
||||
import { StyleProp, StyleSheet, Text, TouchableOpacity, View, ViewStyle } from 'react-native';
|
||||
import { StyleProp, StyleSheet, Text, TouchableOpacity, TouchableOpacityProps, View, ViewStyle } from 'react-native';
|
||||
import { Icon } from '@rneui/themed';
|
||||
|
||||
import { useTheme } from './themes';
|
||||
|
||||
// Define an interface for the props
|
||||
interface ButtonProps {
|
||||
interface ButtonProps extends TouchableOpacityProps {
|
||||
backgroundColor?: string;
|
||||
buttonTextColor?: string;
|
||||
disabled?: boolean;
|
||||
@ -20,7 +19,7 @@ interface ButtonProps {
|
||||
onPress?: () => void;
|
||||
}
|
||||
|
||||
export const Button = forwardRef<TouchableOpacity, ButtonProps>((props, ref) => {
|
||||
export const Button = forwardRef<React.ElementRef<typeof TouchableOpacity>, ButtonProps>((props, ref) => {
|
||||
const { colors } = useTheme();
|
||||
|
||||
let backgroundColor = props.backgroundColor ?? colors.mainColor;
|
||||
@ -56,6 +55,7 @@ export const Button = forwardRef<TouchableOpacity, ButtonProps>((props, ref) =>
|
||||
accessibilityRole="button"
|
||||
onPress={props.onPress}
|
||||
disabled={props.disabled}
|
||||
{...props}
|
||||
>
|
||||
{buttonView}
|
||||
</TouchableOpacity>
|
||||
|
@ -19,7 +19,7 @@ const styleCopyTextToClipboard = StyleSheet.create({
|
||||
},
|
||||
});
|
||||
|
||||
const CopyTextToClipboard = forwardRef<TouchableOpacity, CopyTextToClipboardProps>(({ text, truncated }, ref) => {
|
||||
const CopyTextToClipboard = forwardRef<React.ElementRef<typeof TouchableOpacity>, CopyTextToClipboardProps>(({ text, truncated }, ref) => {
|
||||
const [hasTappedText, setHasTappedText] = useState(false);
|
||||
const [address, setAddress] = useState(text);
|
||||
|
||||
|
@ -1,7 +1,5 @@
|
||||
import React from 'react';
|
||||
import { StyleSheet, Text, View } from 'react-native';
|
||||
|
||||
import loc from '../loc';
|
||||
import PlusIcon from './icons/PlusIcon';
|
||||
import { useTheme } from './themes';
|
||||
|
||||
@ -27,7 +25,7 @@ export const Header: React.FC<HeaderProps> = ({ leftText, isDrawerList, onNewWal
|
||||
return (
|
||||
<View style={[styles.root, styleWithProps.root]}>
|
||||
<Text style={[styles.text, styleWithProps.text]}>{leftText}</Text>
|
||||
{onNewWalletPress && <PlusIcon accessibilityRole="button" accessibilityLabel={loc.wallets.add_title} onPress={onNewWalletPress} />}
|
||||
{onNewWalletPress && <PlusIcon onPress={onNewWalletPress} />}
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
169
components/ManageWalletsListItem.tsx
Normal file
169
components/ManageWalletsListItem.tsx
Normal file
@ -0,0 +1,169 @@
|
||||
import React, { useCallback } from 'react';
|
||||
import { View, StyleSheet, ViewStyle, TouchableOpacity } from 'react-native';
|
||||
import { Icon, ListItem } from '@rneui/base';
|
||||
import { ExtendedTransaction, LightningTransaction, TWallet } from '../class/wallets/types';
|
||||
import { WalletCarouselItem } from './WalletsCarousel';
|
||||
import { TransactionListItem } from './TransactionListItem';
|
||||
import { useTheme } from './themes';
|
||||
import { BitcoinUnit } from '../models/bitcoinUnits';
|
||||
|
||||
enum ItemType {
|
||||
WalletSection = 'wallet',
|
||||
TransactionSection = 'transaction',
|
||||
}
|
||||
|
||||
interface WalletItem {
|
||||
type: ItemType.WalletSection;
|
||||
data: TWallet;
|
||||
}
|
||||
|
||||
interface TransactionItem {
|
||||
type: ItemType.TransactionSection;
|
||||
data: ExtendedTransaction & LightningTransaction;
|
||||
}
|
||||
|
||||
type Item = WalletItem | TransactionItem;
|
||||
|
||||
interface ManageWalletsListItemProps {
|
||||
item: Item;
|
||||
isDraggingDisabled: boolean;
|
||||
drag?: () => void;
|
||||
isPlaceHolder?: boolean;
|
||||
state: { wallets: TWallet[]; searchQuery: string };
|
||||
navigateToWallet: (wallet: TWallet) => void;
|
||||
renderHighlightedText: (text: string, query: string) => JSX.Element;
|
||||
handleDeleteWallet: (wallet: TWallet) => void;
|
||||
handleToggleHideBalance: (wallet: TWallet) => void;
|
||||
}
|
||||
|
||||
interface SwipeContentProps {
|
||||
onPress: () => void;
|
||||
hideBalance?: boolean;
|
||||
colors: any;
|
||||
}
|
||||
|
||||
const LeftSwipeContent: React.FC<SwipeContentProps> = ({ onPress, hideBalance, colors }) => (
|
||||
<TouchableOpacity
|
||||
onPress={onPress}
|
||||
style={[styles.leftButtonContainer, { backgroundColor: colors.buttonAlternativeTextColor } as ViewStyle]}
|
||||
>
|
||||
<Icon name={hideBalance ? 'eye-slash' : 'eye'} color={colors.brandingColor} type="font-awesome-5" />
|
||||
</TouchableOpacity>
|
||||
);
|
||||
|
||||
const RightSwipeContent: React.FC<Partial<SwipeContentProps>> = ({ onPress }) => (
|
||||
<TouchableOpacity onPress={onPress} style={styles.rightButtonContainer as ViewStyle}>
|
||||
<Icon name="delete-outline" color="#FFFFFF" />
|
||||
</TouchableOpacity>
|
||||
);
|
||||
|
||||
const ManageWalletsListItem: React.FC<ManageWalletsListItemProps> = ({
|
||||
item,
|
||||
isDraggingDisabled,
|
||||
drag,
|
||||
state,
|
||||
isPlaceHolder = false,
|
||||
navigateToWallet,
|
||||
renderHighlightedText,
|
||||
handleDeleteWallet,
|
||||
handleToggleHideBalance,
|
||||
}) => {
|
||||
const { colors } = useTheme();
|
||||
|
||||
const onPress = useCallback(() => {
|
||||
if (item.type === ItemType.WalletSection) {
|
||||
navigateToWallet(item.data);
|
||||
}
|
||||
}, [item, navigateToWallet]);
|
||||
|
||||
const leftContent = useCallback(
|
||||
(reset: () => void) => (
|
||||
<LeftSwipeContent
|
||||
onPress={() => {
|
||||
handleToggleHideBalance(item.data as TWallet);
|
||||
reset();
|
||||
}}
|
||||
hideBalance={(item.data as TWallet).hideBalance}
|
||||
colors={colors}
|
||||
/>
|
||||
),
|
||||
[colors, handleToggleHideBalance, item.data],
|
||||
);
|
||||
|
||||
const rightContent = useCallback(
|
||||
(reset: () => void) => (
|
||||
<RightSwipeContent
|
||||
onPress={() => {
|
||||
handleDeleteWallet(item.data as TWallet);
|
||||
reset();
|
||||
}}
|
||||
/>
|
||||
),
|
||||
[handleDeleteWallet, item.data],
|
||||
);
|
||||
|
||||
if (item.type === ItemType.WalletSection) {
|
||||
return (
|
||||
<ListItem.Swipeable
|
||||
leftWidth={80}
|
||||
rightWidth={90}
|
||||
containerStyle={{ backgroundColor: colors.background }}
|
||||
leftContent={leftContent}
|
||||
rightContent={rightContent}
|
||||
>
|
||||
<ListItem.Content
|
||||
style={{
|
||||
backgroundColor: colors.background,
|
||||
}}
|
||||
>
|
||||
<View style={styles.walletCarouselItemContainer}>
|
||||
<WalletCarouselItem
|
||||
item={item.data}
|
||||
handleLongPress={isDraggingDisabled ? undefined : drag}
|
||||
onPress={onPress}
|
||||
animationsEnabled={false}
|
||||
searchQuery={state.searchQuery}
|
||||
isPlaceHolder={isPlaceHolder}
|
||||
renderHighlightedText={renderHighlightedText}
|
||||
/>
|
||||
</View>
|
||||
</ListItem.Content>
|
||||
</ListItem.Swipeable>
|
||||
);
|
||||
} else if (item.type === ItemType.TransactionSection && item.data) {
|
||||
const w = state.wallets.find(wallet => wallet.getTransactions().some((tx: ExtendedTransaction) => tx.hash === item.data.hash));
|
||||
const walletID = w ? w.getID() : '';
|
||||
|
||||
return (
|
||||
<TransactionListItem
|
||||
item={item.data}
|
||||
itemPriceUnit={item.data.walletPreferredBalanceUnit || BitcoinUnit.BTC}
|
||||
walletID={walletID}
|
||||
searchQuery={state.searchQuery}
|
||||
renderHighlightedText={renderHighlightedText}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
console.error('Unrecognized item type:', item);
|
||||
return null;
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
walletCarouselItemContainer: {
|
||||
width: '100%',
|
||||
},
|
||||
leftButtonContainer: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
rightButtonContainer: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
backgroundColor: 'red',
|
||||
},
|
||||
});
|
||||
|
||||
export { ManageWalletsListItem, LeftSwipeContent, RightSwipeContent };
|
@ -20,7 +20,7 @@ type SecondButtonProps = {
|
||||
testID?: string;
|
||||
};
|
||||
|
||||
export const SecondButton = forwardRef<TouchableOpacity, SecondButtonProps>((props, ref) => {
|
||||
export const SecondButton = forwardRef<React.ElementRef<typeof TouchableOpacity>, SecondButtonProps>((props, ref) => {
|
||||
const { colors } = useTheme();
|
||||
let backgroundColor = props.backgroundColor ? props.backgroundColor : colors.buttonGrayBackgroundColor;
|
||||
let fontColor = colors.secondButtonTextColor;
|
||||
|
@ -10,7 +10,7 @@ interface SquareButtonProps {
|
||||
testID?: string;
|
||||
}
|
||||
|
||||
export const SquareButton = forwardRef<TouchableOpacity, SquareButtonProps>((props, ref) => {
|
||||
export const SquareButton = forwardRef<React.ElementRef<typeof TouchableOpacity>, SquareButtonProps>((props, ref) => {
|
||||
const { title, onPress, style, testID } = props;
|
||||
const { colors } = useTheme();
|
||||
|
||||
|
@ -98,7 +98,6 @@ interface WalletCarouselItemProps {
|
||||
isSelectedWallet?: boolean;
|
||||
customStyle?: ViewStyle;
|
||||
horizontal?: boolean;
|
||||
isActive?: boolean;
|
||||
searchQuery?: string;
|
||||
renderHighlightedText?: (text: string, query: string) => JSX.Element;
|
||||
}
|
||||
@ -162,8 +161,32 @@ const iStyles = StyleSheet.create({
|
||||
},
|
||||
});
|
||||
|
||||
interface WalletCarouselItemProps {
|
||||
item: TWallet;
|
||||
onPress: (item: TWallet) => void;
|
||||
handleLongPress?: () => void;
|
||||
isSelectedWallet?: boolean;
|
||||
customStyle?: ViewStyle;
|
||||
horizontal?: boolean;
|
||||
isPlaceHolder?: boolean;
|
||||
searchQuery?: string;
|
||||
renderHighlightedText?: (text: string, query: string) => JSX.Element;
|
||||
animationsEnabled?: boolean;
|
||||
}
|
||||
|
||||
export const WalletCarouselItem: React.FC<WalletCarouselItemProps> = React.memo(
|
||||
({ item, onPress, handleLongPress, isSelectedWallet, customStyle, horizontal, searchQuery, renderHighlightedText }) => {
|
||||
({
|
||||
item,
|
||||
onPress,
|
||||
handleLongPress,
|
||||
isSelectedWallet,
|
||||
customStyle,
|
||||
horizontal,
|
||||
searchQuery,
|
||||
renderHighlightedText,
|
||||
animationsEnabled = true,
|
||||
isPlaceHolder = false,
|
||||
}) => {
|
||||
const scaleValue = useRef(new Animated.Value(1.0)).current;
|
||||
const { colors } = useTheme();
|
||||
const { walletTransactionUpdateStatus } = useStorage();
|
||||
@ -172,22 +195,26 @@ export const WalletCarouselItem: React.FC<WalletCarouselItemProps> = React.memo(
|
||||
const { isLargeScreen } = useIsLargeScreen();
|
||||
|
||||
const onPressedIn = useCallback(() => {
|
||||
Animated.spring(scaleValue, {
|
||||
toValue: 0.95,
|
||||
useNativeDriver: true,
|
||||
friction: 3,
|
||||
tension: 100,
|
||||
}).start();
|
||||
}, [scaleValue]);
|
||||
if (animationsEnabled) {
|
||||
Animated.spring(scaleValue, {
|
||||
toValue: 0.95,
|
||||
useNativeDriver: true,
|
||||
friction: 3,
|
||||
tension: 100,
|
||||
}).start();
|
||||
}
|
||||
}, [scaleValue, animationsEnabled]);
|
||||
|
||||
const onPressedOut = useCallback(() => {
|
||||
Animated.spring(scaleValue, {
|
||||
toValue: 1.0,
|
||||
useNativeDriver: true,
|
||||
friction: 3,
|
||||
tension: 100,
|
||||
}).start();
|
||||
}, [scaleValue]);
|
||||
if (animationsEnabled) {
|
||||
Animated.spring(scaleValue, {
|
||||
toValue: 1.0,
|
||||
useNativeDriver: true,
|
||||
friction: 3,
|
||||
tension: 100,
|
||||
}).start();
|
||||
}
|
||||
}, [scaleValue, animationsEnabled]);
|
||||
|
||||
const handlePress = useCallback(() => {
|
||||
onPressedOut();
|
||||
@ -239,33 +266,37 @@ export const WalletCarouselItem: React.FC<WalletCarouselItemProps> = React.memo(
|
||||
<LinearGradient colors={WalletGradient.gradientsFor(item.type)} style={iStyles.grad}>
|
||||
<Image defaultSource={image} source={image} style={iStyles.image} />
|
||||
<Text style={iStyles.br} />
|
||||
<Text numberOfLines={1} style={[iStyles.label, { color: colors.inverseForegroundColor }]}>
|
||||
{renderHighlightedText && searchQuery ? renderHighlightedText(item.getLabel(), searchQuery) : item.getLabel()}
|
||||
</Text>
|
||||
<View style={iStyles.balanceContainer}>
|
||||
{item.hideBalance ? (
|
||||
<>
|
||||
<BlueSpacing10 />
|
||||
<BlurredBalanceView />
|
||||
</>
|
||||
) : (
|
||||
<Text
|
||||
numberOfLines={1}
|
||||
adjustsFontSizeToFit
|
||||
key={`${balance}`} // force component recreation on balance change. To fix right-to-left languages, like Farsi
|
||||
style={[iStyles.balance, { color: colors.inverseForegroundColor }]}
|
||||
>
|
||||
{`${balance} `}
|
||||
{!isPlaceHolder && (
|
||||
<>
|
||||
<Text numberOfLines={1} style={[iStyles.label, { color: colors.inverseForegroundColor }]}>
|
||||
{renderHighlightedText && searchQuery ? renderHighlightedText(item.getLabel(), searchQuery) : item.getLabel()}
|
||||
</Text>
|
||||
)}
|
||||
</View>
|
||||
<Text style={iStyles.br} />
|
||||
<Text numberOfLines={1} style={[iStyles.latestTx, { color: colors.inverseForegroundColor }]}>
|
||||
{loc.wallets.list_latest_transaction}
|
||||
</Text>
|
||||
<Text numberOfLines={1} style={[iStyles.latestTxTime, { color: colors.inverseForegroundColor }]}>
|
||||
{latestTransactionText}
|
||||
</Text>
|
||||
<View style={iStyles.balanceContainer}>
|
||||
{item.hideBalance ? (
|
||||
<>
|
||||
<BlueSpacing10 />
|
||||
<BlurredBalanceView />
|
||||
</>
|
||||
) : (
|
||||
<Text
|
||||
numberOfLines={1}
|
||||
adjustsFontSizeToFit
|
||||
key={`${balance}`} // force component recreation on balance change. To fix right-to-left languages, like Farsi
|
||||
style={[iStyles.balance, { color: colors.inverseForegroundColor }]}
|
||||
>
|
||||
{`${balance} `}
|
||||
</Text>
|
||||
)}
|
||||
</View>
|
||||
<Text style={iStyles.br} />
|
||||
<Text numberOfLines={1} style={[iStyles.latestTx, { color: colors.inverseForegroundColor }]}>
|
||||
{loc.wallets.list_latest_transaction}
|
||||
</Text>
|
||||
<Text numberOfLines={1} style={[iStyles.latestTxTime, { color: colors.inverseForegroundColor }]}>
|
||||
{latestTransactionText}
|
||||
</Text>
|
||||
</>
|
||||
)}
|
||||
</LinearGradient>
|
||||
</View>
|
||||
</Pressable>
|
||||
|
@ -1,8 +1,13 @@
|
||||
import React from 'react';
|
||||
import { StyleSheet, TouchableOpacity } from 'react-native';
|
||||
import { StyleSheet, TouchableOpacity, ViewStyle } from 'react-native';
|
||||
import { Icon } from '@rneui/themed';
|
||||
|
||||
import { useTheme } from '../themes';
|
||||
import loc from '../../loc';
|
||||
|
||||
type PlusIconProps = {
|
||||
onPress: () => void;
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
ball: {
|
||||
@ -11,10 +16,10 @@ const styles = StyleSheet.create({
|
||||
borderRadius: 15,
|
||||
justifyContent: 'center',
|
||||
alignContent: 'center',
|
||||
},
|
||||
} as ViewStyle,
|
||||
});
|
||||
|
||||
const PlusIcon = props => {
|
||||
const PlusIcon: React.FC<PlusIconProps> = ({ onPress }) => {
|
||||
const { colors } = useTheme();
|
||||
const stylesHook = StyleSheet.create({
|
||||
ball: {
|
||||
@ -23,7 +28,12 @@ const PlusIcon = props => {
|
||||
});
|
||||
|
||||
return (
|
||||
<TouchableOpacity style={[styles.ball, stylesHook.ball]} onPress={props.onPress}>
|
||||
<TouchableOpacity
|
||||
style={[styles.ball, stylesHook.ball]}
|
||||
accessibilityLabel={loc.wallets.add_title}
|
||||
onPress={onPress}
|
||||
accessibilityRole="button"
|
||||
>
|
||||
<Icon name="add" size={22} type="ionicons" color={colors.foregroundColor} />
|
||||
</TouchableOpacity>
|
||||
);
|
@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import { StyleSheet, View } from 'react-native';
|
||||
import { StyleSheet, View, ViewStyle } from 'react-native';
|
||||
import { Icon } from '@rneui/themed';
|
||||
|
||||
import { useTheme } from '../themes';
|
||||
@ -7,20 +7,20 @@ import { useTheme } from '../themes';
|
||||
const styles = StyleSheet.create({
|
||||
boxIncoming: {
|
||||
position: 'relative',
|
||||
},
|
||||
} as ViewStyle,
|
||||
ballOutgoingExpired: {
|
||||
width: 30,
|
||||
height: 30,
|
||||
borderRadius: 15,
|
||||
justifyContent: 'center',
|
||||
},
|
||||
} as ViewStyle,
|
||||
icon: {
|
||||
left: 0,
|
||||
top: 0,
|
||||
},
|
||||
});
|
||||
|
||||
const TransactionExpiredIcon = props => {
|
||||
const TransactionExpiredIcon: React.FC = () => {
|
||||
const { colors } = useTheme();
|
||||
const stylesHooks = StyleSheet.create({
|
||||
ballOutgoingExpired: {
|
@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import { StyleSheet, View } from 'react-native';
|
||||
import { StyleSheet, View, ViewStyle } from 'react-native';
|
||||
import { Icon } from '@rneui/themed';
|
||||
|
||||
import { useTheme } from '../themes';
|
||||
@ -7,17 +7,17 @@ import { useTheme } from '../themes';
|
||||
const styles = StyleSheet.create({
|
||||
boxIncoming: {
|
||||
position: 'relative',
|
||||
},
|
||||
} as ViewStyle,
|
||||
ballIncoming: {
|
||||
width: 30,
|
||||
height: 30,
|
||||
borderRadius: 15,
|
||||
transform: [{ rotate: '-45deg' }],
|
||||
justifyContent: 'center',
|
||||
},
|
||||
} as ViewStyle,
|
||||
});
|
||||
|
||||
const TransactionIncomingIcon = props => {
|
||||
const TransactionIncomingIcon: React.FC = () => {
|
||||
const { colors } = useTheme();
|
||||
const stylesHooks = StyleSheet.create({
|
||||
ballIncoming: {
|
@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import { StyleSheet, View } from 'react-native';
|
||||
import { StyleSheet, View, ViewStyle } from 'react-native';
|
||||
import { Icon } from '@rneui/themed';
|
||||
|
||||
import { useTheme } from '../themes';
|
||||
@ -7,19 +7,19 @@ import { useTheme } from '../themes';
|
||||
const styles = StyleSheet.create({
|
||||
boxIncoming: {
|
||||
position: 'relative',
|
||||
},
|
||||
} as ViewStyle,
|
||||
ballOutgoingWithoutRotate: {
|
||||
width: 30,
|
||||
height: 30,
|
||||
borderRadius: 15,
|
||||
},
|
||||
} as ViewStyle,
|
||||
icon: {
|
||||
left: 0,
|
||||
marginTop: 6,
|
||||
},
|
||||
});
|
||||
|
||||
const TransactionOffchainIcon = props => {
|
||||
const TransactionOffchainIcon: React.FC = () => {
|
||||
const { colors } = useTheme();
|
||||
const stylesHooks = StyleSheet.create({
|
||||
ballOutgoingWithoutRotate: {
|
@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import { StyleSheet, View } from 'react-native';
|
||||
import { StyleSheet, View, ViewStyle } from 'react-native';
|
||||
import { Icon } from '@rneui/themed';
|
||||
|
||||
import { useTheme } from '../themes';
|
||||
@ -7,19 +7,19 @@ import { useTheme } from '../themes';
|
||||
const styles = StyleSheet.create({
|
||||
boxIncoming: {
|
||||
position: 'relative',
|
||||
},
|
||||
} as ViewStyle,
|
||||
ballIncomingWithoutRotate: {
|
||||
width: 30,
|
||||
height: 30,
|
||||
borderRadius: 15,
|
||||
},
|
||||
} as ViewStyle,
|
||||
icon: {
|
||||
left: 0,
|
||||
marginTop: 6,
|
||||
},
|
||||
});
|
||||
|
||||
const TransactionOffchainIncomingIcon = props => {
|
||||
const TransactionOffchainIncomingIcon: React.FC = () => {
|
||||
const { colors } = useTheme();
|
||||
const stylesHooks = StyleSheet.create({
|
||||
ballIncomingWithoutRotate: {
|
@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import { StyleSheet, View } from 'react-native';
|
||||
import { StyleSheet, View, ViewStyle } from 'react-native';
|
||||
import { Icon } from '@rneui/themed';
|
||||
|
||||
import { useTheme } from '../themes';
|
||||
@ -7,14 +7,14 @@ import { useTheme } from '../themes';
|
||||
const styles = StyleSheet.create({
|
||||
boxIncoming: {
|
||||
position: 'relative',
|
||||
},
|
||||
} as ViewStyle,
|
||||
ballIncoming: {
|
||||
width: 30,
|
||||
height: 30,
|
||||
borderRadius: 15,
|
||||
transform: [{ rotate: '-45deg' }],
|
||||
justifyContent: 'center',
|
||||
},
|
||||
} as ViewStyle,
|
||||
icon: {
|
||||
left: 0,
|
||||
top: 0,
|
||||
@ -22,7 +22,7 @@ const styles = StyleSheet.create({
|
||||
},
|
||||
});
|
||||
|
||||
const TransactionOnchainIcon = props => {
|
||||
const TransactionOnchainIcon: React.FC = () => {
|
||||
const { colors } = useTheme();
|
||||
const stylesBlueIconHooks = StyleSheet.create({
|
||||
ballIncoming: {
|
@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import { StyleSheet, View } from 'react-native';
|
||||
import { StyleSheet, View, ViewStyle } from 'react-native';
|
||||
import { Icon } from '@rneui/themed';
|
||||
|
||||
import { useTheme } from '../themes';
|
||||
@ -7,17 +7,17 @@ import { useTheme } from '../themes';
|
||||
const styles = StyleSheet.create({
|
||||
boxIncoming: {
|
||||
position: 'relative',
|
||||
},
|
||||
} as ViewStyle,
|
||||
ballOutgoing: {
|
||||
width: 30,
|
||||
height: 30,
|
||||
borderRadius: 15,
|
||||
transform: [{ rotate: '225deg' }],
|
||||
justifyContent: 'center',
|
||||
},
|
||||
} as ViewStyle,
|
||||
});
|
||||
|
||||
const TransactionOutgoingIcon = props => {
|
||||
const TransactionOutgoingIcon: React.FC = () => {
|
||||
const { colors } = useTheme();
|
||||
const stylesBlueIconHooks = StyleSheet.create({
|
||||
ballOutgoing: {
|
@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import { StyleSheet, View } from 'react-native';
|
||||
import { StyleSheet, View, ViewStyle } from 'react-native';
|
||||
import { Icon } from '@rneui/themed';
|
||||
|
||||
import { useTheme } from '../themes';
|
||||
@ -7,19 +7,19 @@ import { useTheme } from '../themes';
|
||||
const styles = StyleSheet.create({
|
||||
boxIncoming: {
|
||||
position: 'relative',
|
||||
},
|
||||
} as ViewStyle,
|
||||
ball: {
|
||||
width: 30,
|
||||
height: 30,
|
||||
borderRadius: 15,
|
||||
},
|
||||
} as ViewStyle,
|
||||
icon: {
|
||||
left: 0,
|
||||
top: 7,
|
||||
},
|
||||
});
|
||||
|
||||
const TransactionPendingIcon = props => {
|
||||
const TransactionPendingIcon: React.FC = () => {
|
||||
const { colors } = useTheme();
|
||||
const stylesHook = StyleSheet.create({
|
||||
ball: {
|
BIN
img/camera-rotate-solid@1x.png
Normal file
BIN
img/camera-rotate-solid@1x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 30 KiB |
BIN
img/camera-rotate-solid@2x.png
Normal file
BIN
img/camera-rotate-solid@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 87 KiB |
BIN
img/camera-rotate-solid@3x.png
Normal file
BIN
img/camera-rotate-solid@3x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 150 KiB |
BIN
img/flash-off.png
Normal file
BIN
img/flash-off.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.7 KiB |
BIN
img/flash-on.png
Normal file
BIN
img/flash-on.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.1 KiB |
@ -131,7 +131,7 @@
|
||||
B4D0B2682C1DED67006B6B1B /* ReceiveMethod.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4D0B2672C1DED67006B6B1B /* ReceiveMethod.swift */; };
|
||||
B4EE583C226703320003363C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B40D4E35225841ED00428FCC /* Assets.xcassets */; };
|
||||
B4EFF73B2C3F6C5E0095D655 /* MockData.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4EFF73A2C3F6C5E0095D655 /* MockData.swift */; };
|
||||
C978A716948AB7DEC5B6F677 /* (null) in Frameworks */ = {isa = PBXBuildFile; };
|
||||
C978A716948AB7DEC5B6F677 /* BuildFile in Frameworks */ = {isa = PBXBuildFile; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
@ -353,6 +353,7 @@
|
||||
B49038D82B8FBAD300A8164A /* BlueWalletUITest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlueWalletUITest.swift; sourceTree = "<group>"; };
|
||||
B4AB225C2B02AD12001F4328 /* XMLParserDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = XMLParserDelegate.swift; sourceTree = "<group>"; };
|
||||
B4B1A4612BFA73110072E3BB /* WidgetHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetHelper.swift; sourceTree = "<group>"; };
|
||||
B4B31A352C77BBA000663334 /* nb */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nb; path = nb.lproj/Interface.strings; sourceTree = "<group>"; };
|
||||
B4D0B2612C1DEA11006B6B1B /* ReceivePageInterfaceController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReceivePageInterfaceController.swift; sourceTree = "<group>"; };
|
||||
B4D0B2632C1DEA99006B6B1B /* ReceiveType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReceiveType.swift; sourceTree = "<group>"; };
|
||||
B4D0B2652C1DEB7F006B6B1B /* ReceiveInterfaceMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReceiveInterfaceMode.swift; sourceTree = "<group>"; };
|
||||
@ -383,7 +384,7 @@
|
||||
files = (
|
||||
782F075B5DD048449E2DECE9 /* libz.tbd in Frameworks */,
|
||||
764B49B1420D4AEB8109BF62 /* libsqlite3.0.tbd in Frameworks */,
|
||||
C978A716948AB7DEC5B6F677 /* (null) in Frameworks */,
|
||||
C978A716948AB7DEC5B6F677 /* BuildFile in Frameworks */,
|
||||
773E382FE62E836172AAB98B /* libPods-BlueWallet.a in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@ -961,6 +962,7 @@
|
||||
uk,
|
||||
tr,
|
||||
xh,
|
||||
nb,
|
||||
);
|
||||
mainGroup = 83CBB9F61A601CBA00E9B192;
|
||||
packageReferences = (
|
||||
@ -1339,6 +1341,7 @@
|
||||
6D294A9924D512690039E22B /* uk */,
|
||||
6D294A9B24D512770039E22B /* tr */,
|
||||
6D294A9D24D5127F0039E22B /* xh */,
|
||||
B4B31A352C77BBA000663334 /* nb */,
|
||||
);
|
||||
name = Interface.storyboard;
|
||||
sourceTree = "<group>";
|
||||
@ -1357,7 +1360,7 @@
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
|
||||
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
CURRENT_PROJECT_VERSION = 1703136694;
|
||||
CURRENT_PROJECT_VERSION = 1703136697;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = A7W54YZ4WU;
|
||||
@ -1382,7 +1385,7 @@
|
||||
"$(SDKROOT)/System/iOSSupport/usr/lib/swift",
|
||||
"$(inherited)",
|
||||
);
|
||||
MARKETING_VERSION = 7.0.3;
|
||||
MARKETING_VERSION = 7.0.4;
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
"-ObjC",
|
||||
@ -1417,7 +1420,7 @@
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
|
||||
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Distribution";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
CURRENT_PROJECT_VERSION = 1703136694;
|
||||
CURRENT_PROJECT_VERSION = 1703136697;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = A7W54YZ4WU;
|
||||
@ -1437,7 +1440,7 @@
|
||||
"$(SDKROOT)/System/iOSSupport/usr/lib/swift",
|
||||
"$(inherited)",
|
||||
);
|
||||
MARKETING_VERSION = 7.0.3;
|
||||
MARKETING_VERSION = 7.0.4;
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
"-ObjC",
|
||||
@ -1473,7 +1476,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
CURRENT_PROJECT_VERSION = 1703136694;
|
||||
CURRENT_PROJECT_VERSION = 1703136697;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
@ -1486,7 +1489,7 @@
|
||||
"$(SDKROOT)/System/iOSSupport/usr/lib/swift",
|
||||
"$(inherited)",
|
||||
);
|
||||
MARKETING_VERSION = 7.0.3;
|
||||
MARKETING_VERSION = 7.0.4;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRESERVE_DEAD_CODE_INITS_AND_TERMS = YES;
|
||||
@ -1516,7 +1519,7 @@
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1703136694;
|
||||
CURRENT_PROJECT_VERSION = 1703136697;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
DEVELOPMENT_TEAM = "";
|
||||
@ -1529,7 +1532,7 @@
|
||||
"$(SDKROOT)/System/iOSSupport/usr/lib/swift",
|
||||
"$(inherited)",
|
||||
);
|
||||
MARKETING_VERSION = 7.0.3;
|
||||
MARKETING_VERSION = 7.0.4;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRESERVE_DEAD_CODE_INITS_AND_TERMS = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = io.bluewallet.bluewallet.Stickers;
|
||||
@ -1560,7 +1563,7 @@
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
CURRENT_PROJECT_VERSION = 1703136694;
|
||||
CURRENT_PROJECT_VERSION = 1703136697;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
@ -1579,7 +1582,7 @@
|
||||
"$(SDKROOT)/System/iOSSupport/usr/lib/swift",
|
||||
"$(inherited)",
|
||||
);
|
||||
MARKETING_VERSION = 7.0.3;
|
||||
MARKETING_VERSION = 7.0.4;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRESERVE_DEAD_CODE_INITS_AND_TERMS = YES;
|
||||
@ -1616,7 +1619,7 @@
|
||||
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Distribution";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1703136694;
|
||||
CURRENT_PROJECT_VERSION = 1703136697;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
DEVELOPMENT_TEAM = "";
|
||||
@ -1635,7 +1638,7 @@
|
||||
"$(SDKROOT)/System/iOSSupport/usr/lib/swift",
|
||||
"$(inherited)",
|
||||
);
|
||||
MARKETING_VERSION = 7.0.3;
|
||||
MARKETING_VERSION = 7.0.4;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRESERVE_DEAD_CODE_INITS_AND_TERMS = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = io.bluewallet.bluewallet.MarketWidget;
|
||||
@ -1715,6 +1718,7 @@
|
||||
OTHER_LDFLAGS = "$(inherited)";
|
||||
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) DEBUG";
|
||||
SWIFT_VERSION = 5.0;
|
||||
USE_HERMES = true;
|
||||
};
|
||||
@ -1798,7 +1802,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
"CODE_SIGN_IDENTITY[sdk=watchos*]" = "iPhone Developer";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
CURRENT_PROJECT_VERSION = 1703136694;
|
||||
CURRENT_PROJECT_VERSION = 1703136697;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
@ -1815,7 +1819,7 @@
|
||||
"$(SDKROOT)/System/iOSSupport/usr/lib/swift",
|
||||
"$(inherited)",
|
||||
);
|
||||
MARKETING_VERSION = 7.0.3;
|
||||
MARKETING_VERSION = 7.0.4;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRESERVE_DEAD_CODE_INITS_AND_TERMS = YES;
|
||||
@ -1848,7 +1852,7 @@
|
||||
"CODE_SIGN_IDENTITY[sdk=watchos*]" = "iPhone Distribution";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1703136694;
|
||||
CURRENT_PROJECT_VERSION = 1703136697;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
DEVELOPMENT_TEAM = "";
|
||||
@ -1865,7 +1869,7 @@
|
||||
"$(SDKROOT)/System/iOSSupport/usr/lib/swift",
|
||||
"$(inherited)",
|
||||
);
|
||||
MARKETING_VERSION = 7.0.3;
|
||||
MARKETING_VERSION = 7.0.4;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRESERVE_DEAD_CODE_INITS_AND_TERMS = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = io.bluewallet.bluewallet.watch.extension;
|
||||
@ -1897,7 +1901,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
"CODE_SIGN_IDENTITY[sdk=watchos*]" = "iPhone Developer";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
CURRENT_PROJECT_VERSION = 1703136694;
|
||||
CURRENT_PROJECT_VERSION = 1703136697;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
@ -1910,7 +1914,7 @@
|
||||
"$(SDKROOT)/System/iOSSupport/usr/lib/swift",
|
||||
"$(inherited)",
|
||||
);
|
||||
MARKETING_VERSION = 7.0.3;
|
||||
MARKETING_VERSION = 7.0.4;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRESERVE_DEAD_CODE_INITS_AND_TERMS = YES;
|
||||
@ -1945,7 +1949,7 @@
|
||||
"CODE_SIGN_IDENTITY[sdk=watchos*]" = "iPhone Distribution";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1703136694;
|
||||
CURRENT_PROJECT_VERSION = 1703136697;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
DEVELOPMENT_TEAM = "";
|
||||
@ -1958,7 +1962,7 @@
|
||||
"$(SDKROOT)/System/iOSSupport/usr/lib/swift",
|
||||
"$(inherited)",
|
||||
);
|
||||
MARKETING_VERSION = 7.0.3;
|
||||
MARKETING_VERSION = 7.0.4;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRESERVE_DEAD_CODE_INITS_AND_TERMS = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = io.bluewallet.bluewallet.watch;
|
||||
|
105
ios/BlueWalletWatch/nb.lproj/Interface.strings
Normal file
105
ios/BlueWalletWatch/nb.lproj/Interface.strings
Normal file
@ -0,0 +1,105 @@
|
||||
|
||||
/* Class = "WKInterfaceButton"; title = "Amount"; ObjectID = "0Hm-hv-Yi3"; */
|
||||
"0Hm-hv-Yi3.title" = "Amount";
|
||||
|
||||
/* Class = "WKInterfaceButton"; title = "8"; ObjectID = "3FQ-tZ-9kd"; */
|
||||
"3FQ-tZ-9kd.title" = "8";
|
||||
|
||||
/* Class = "WKInterfaceButton"; title = "Create"; ObjectID = "6eh-lx-UEe"; */
|
||||
"6eh-lx-UEe.title" = "Create";
|
||||
|
||||
/* Class = "WKInterfaceButton"; title = "Create Invoice"; ObjectID = "7bc-tt-Pab"; */
|
||||
"7bc-tt-Pab.title" = "Create Invoice";
|
||||
|
||||
/* Class = "WKInterfaceButton"; title = "5"; ObjectID = "AA6-Gq-qRe"; */
|
||||
"AA6-Gq-qRe.title" = "5";
|
||||
|
||||
/* Class = "WKInterfaceLabel"; text = "memo"; ObjectID = "AJ8-p9-ID7"; */
|
||||
"AJ8-p9-ID7.text" = "memo";
|
||||
|
||||
/* Class = "WKInterfaceController"; title = "BlueWallet"; ObjectID = "AgC-eL-Hgc"; */
|
||||
"AgC-eL-Hgc.title" = "BlueWallet";
|
||||
|
||||
/* Class = "WKInterfaceLabel"; text = "Time"; ObjectID = "GqE-KB-TRD"; */
|
||||
"GqE-KB-TRD.text" = "Time";
|
||||
|
||||
/* Class = "WKInterfaceLabel"; text = "No wallets available. Please, add one by opening BlueWallet on your iPhone."; ObjectID = "I2I-8t-hp3"; */
|
||||
"I2I-8t-hp3.text" = "No wallets available. Please, add one by opening BlueWallet on your iPhone.";
|
||||
|
||||
/* Class = "WKInterfaceLabel"; text = "Alert Label"; ObjectID = "IdU-wH-bcW"; */
|
||||
"IdU-wH-bcW.text" = "Alert Label";
|
||||
|
||||
/* Class = "WKInterfaceLabel"; text = "Label"; ObjectID = "JMO-XZ-1si"; */
|
||||
"JMO-XZ-1si.text" = "Label";
|
||||
|
||||
/* Class = "WKInterfaceButton"; title = "9"; ObjectID = "NJM-uR-nyO"; */
|
||||
"NJM-uR-nyO.title" = "9";
|
||||
|
||||
/* Class = "WKInterfaceButton"; title = "6"; ObjectID = "Nt9-we-M9f"; */
|
||||
"Nt9-we-M9f.title" = "6";
|
||||
|
||||
/* Class = "WKInterfaceLabel"; text = "Wallet"; ObjectID = "PQi-JV-aYW"; */
|
||||
"PQi-JV-aYW.text" = "Wallet";
|
||||
|
||||
/* Class = "WKInterfaceLabel"; text = "Balance"; ObjectID = "QYx-3e-6zf"; */
|
||||
"QYx-3e-6zf.text" = "Balance";
|
||||
|
||||
/* Class = "WKInterfaceMenuItem"; title = "Customize"; ObjectID = "RHB-IJ-Utd"; */
|
||||
"RHB-IJ-Utd.title" = "Customize";
|
||||
|
||||
/* Class = "WKInterfaceButton"; title = "0"; ObjectID = "S1H-Id-l6g"; */
|
||||
"S1H-Id-l6g.title" = "0";
|
||||
|
||||
/* Class = "WKInterfaceButton"; title = "3"; ObjectID = "TKO-lc-aYf"; */
|
||||
"TKO-lc-aYf.title" = "3";
|
||||
|
||||
/* Class = "WKInterfaceLabel"; text = "Balance"; ObjectID = "WTr-jJ-w7L"; */
|
||||
"WTr-jJ-w7L.text" = "Balance";
|
||||
|
||||
/* Class = "WKInterfaceController"; title = "Transactions"; ObjectID = "XWa-4i-Abg"; */
|
||||
"XWa-4i-Abg.title" = "Transactions";
|
||||
|
||||
/* Class = "WKInterfaceButton"; title = "2"; ObjectID = "aUI-EE-NVw"; */
|
||||
"aUI-EE-NVw.title" = "2";
|
||||
|
||||
/* Class = "WKInterfaceButton"; title = "Receive"; ObjectID = "bPO-h8-ccD"; */
|
||||
"bPO-h8-ccD.title" = "Receive";
|
||||
|
||||
/* Class = "WKInterfaceLabel"; text = "Label"; ObjectID = "c3W-8T-srG"; */
|
||||
"c3W-8T-srG.text" = "Label";
|
||||
|
||||
/* Class = "WKInterfaceController"; title = "Receive"; ObjectID = "egq-Yw-qK5"; */
|
||||
"egq-Yw-qK5.title" = "Receive";
|
||||
|
||||
/* Class = "WKInterfaceButton"; title = "Description"; ObjectID = "fcI-6Z-moQ"; */
|
||||
"fcI-6Z-moQ.title" = "Description";
|
||||
|
||||
/* Class = "WKInterfaceButton"; title = "."; ObjectID = "g6Z-9t-ahQ"; */
|
||||
"g6Z-9t-ahQ.title" = ".";
|
||||
|
||||
/* Class = "WKInterfaceButton"; title = "1"; ObjectID = "ghD-Jq-ubw"; */
|
||||
"ghD-Jq-ubw.title" = "1";
|
||||
|
||||
/* Class = "WKInterfaceButton"; title = "View XPUB"; ObjectID = "j0O-fq-mwp"; */
|
||||
"j0O-fq-mwp.title" = "View XPUB";
|
||||
|
||||
/* Class = "WKInterfaceButton"; title = "4"; ObjectID = "kH2-N1-Hbe"; */
|
||||
"kH2-N1-Hbe.title" = "4";
|
||||
|
||||
/* Class = "WKInterfaceLabel"; text = "Creating Invoice..."; ObjectID = "n5f-iL-ib7"; */
|
||||
"n5f-iL-ib7.text" = "Creating Invoice...";
|
||||
|
||||
/* Class = "WKInterfaceButton"; title = "7"; ObjectID = "ohU-B0-mvg"; */
|
||||
"ohU-B0-mvg.title" = "7";
|
||||
|
||||
/* Class = "WKInterfaceLabel"; text = "No Transactions"; ObjectID = "pi4-Bk-Jiq"; */
|
||||
"pi4-Bk-Jiq.text" = "No Transactions";
|
||||
|
||||
/* Class = "WKInterfaceButton"; title = "<"; ObjectID = "q8Q-tK-nzd"; */
|
||||
"q8Q-tK-nzd.title" = "<";
|
||||
|
||||
/* Class = "WKInterfaceLabel"; text = "Wallet"; ObjectID = "qpj-I1-cWt"; */
|
||||
"qpj-I1-cWt.text" = "Wallet";
|
||||
|
||||
/* Class = "WKInterfaceLabel"; text = "Amount"; ObjectID = "sAS-LI-RY7"; */
|
||||
"sAS-LI-RY7.text" = "Amount";
|
@ -19,6 +19,7 @@ require Pod::Executable.execute_command('node', ['-p',
|
||||
)', __dir__]).strip
|
||||
|
||||
workspace 'BlueWallet'
|
||||
project 'BlueWallet.xcodeproj'
|
||||
platform :ios, min_ios_version_supported
|
||||
prepare_react_native_project!
|
||||
setup_permissions(['Camera', 'Notifications'])
|
||||
|
2887
ios/Podfile.lock
2887
ios/Podfile.lock
File diff suppressed because it is too large
Load Diff
@ -85,34 +85,52 @@ platform :ios do
|
||||
end
|
||||
|
||||
desc "Fetch development certificates and provisioning profiles for Mac Catalyst"
|
||||
lane :fetch_dev_profiles_catalyst do
|
||||
match(
|
||||
type: "development",
|
||||
platform: "catalyst",
|
||||
app_identifier: app_identifiers,
|
||||
readonly: true
|
||||
)
|
||||
end
|
||||
lane :fetch_dev_profiles_catalyst do
|
||||
match(
|
||||
type: "development",
|
||||
platform: "catalyst",
|
||||
app_identifier: app_identifiers,
|
||||
readonly: true
|
||||
)
|
||||
end
|
||||
|
||||
desc "Fetch App Store certificates and provisioning profiles for Mac Catalyst"
|
||||
lane :fetch_appstore_profiles_catalyst do
|
||||
match(
|
||||
type: "appstore",
|
||||
platform: "catalyst",
|
||||
app_identifier: app_identifiers,
|
||||
readonly: true
|
||||
)
|
||||
end
|
||||
|
||||
desc "Fetch App Store certificates and provisioning profiles for Mac Catalyst"
|
||||
lane :fetch_appstore_profiles_catalyst do
|
||||
match(
|
||||
type: "appstore",
|
||||
platform: "catalyst",
|
||||
app_identifier: app_identifiers,
|
||||
readonly: true
|
||||
)
|
||||
end
|
||||
desc "Setup provisioning profiles for Mac Catalyst"
|
||||
lane :setup_catalyst_provisioning_profiles do
|
||||
app_identifiers.each do |app_identifier|
|
||||
match(
|
||||
type: "development",
|
||||
platform: "catalyst",
|
||||
app_identifier: app_identifier,
|
||||
readonly: false,
|
||||
force_for_new_devices: true
|
||||
)
|
||||
|
||||
match(
|
||||
type: "appstore",
|
||||
platform: "catalyst",
|
||||
app_identifier: app_identifier,
|
||||
readonly: false
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
desc "Clear derived data"
|
||||
desc "Clear derived data"
|
||||
lane :clear_derived_data_lane do
|
||||
UI.message("Clearing derived data...")
|
||||
clear_derived_data
|
||||
end
|
||||
end
|
||||
|
||||
desc "Increment build number"
|
||||
desc "Increment build number"
|
||||
lane :increment_build_number_lane do
|
||||
UI.message("Incrementing build number to current timestamp...")
|
||||
|
||||
@ -120,7 +138,7 @@ desc "Increment build number"
|
||||
increment_build_number(
|
||||
xcodeproj: "BlueWallet.xcodeproj",
|
||||
build_number: ENV["NEW_BUILD_NUMBER"]
|
||||
)
|
||||
)
|
||||
|
||||
UI.message("Build number set to: #{ENV['NEW_BUILD_NUMBER']}")
|
||||
end
|
||||
@ -215,111 +233,117 @@ desc "Increment build number"
|
||||
last_commit = last_git_commit
|
||||
already_built_flag = ".already_built_#{last_commit[:sha]}"
|
||||
File.write(already_built_flag, Time.now.to_s)
|
||||
end
|
||||
end
|
||||
|
||||
desc "Fetch development certificates and provisioning profiles for Mac Catalyst"
|
||||
lane :fetch_dev_profiles_catalyst do
|
||||
match(
|
||||
type: "development",
|
||||
platform: "catalyst",
|
||||
app_identifier: app_identifiers,
|
||||
readonly: true
|
||||
)
|
||||
end
|
||||
|
||||
desc "Fetch App Store certificates and provisioning profiles for Mac Catalyst"
|
||||
lane :fetch_appstore_profiles_catalyst do
|
||||
match(
|
||||
type: "appstore",
|
||||
platform: "catalyst",
|
||||
app_identifier: app_identifiers,
|
||||
readonly: true
|
||||
)
|
||||
desc "Update 'What's New' section in App Store Connect for the 'Prepare for Submission' version"
|
||||
lane :update_release_notes do |options|
|
||||
require 'spaceship'
|
||||
|
||||
UI.message("Logging in to App Store Connect...")
|
||||
Spaceship::ConnectAPI.login
|
||||
|
||||
app = Spaceship::ConnectAPI::App.find(app_identifiers.first)
|
||||
|
||||
unless app
|
||||
UI.user_error!("Could not find the app with identifier: #{app_identifiers.first}")
|
||||
end
|
||||
|
||||
desc "Setup provisioning profiles for Mac Catalyst"
|
||||
lane :setup_catalyst_provisioning_profiles do
|
||||
app_identifiers.each do |app_identifier|
|
||||
match(
|
||||
type: "development",
|
||||
platform: "catalyst",
|
||||
app_identifier: app_identifier,
|
||||
readonly: false,
|
||||
force_for_new_devices: true
|
||||
)
|
||||
|
||||
match(
|
||||
type: "appstore",
|
||||
platform: "catalyst",
|
||||
app_identifier: app_identifier,
|
||||
readonly: false
|
||||
)
|
||||
end
|
||||
|
||||
desc "Update 'What's New' section in App Store Connect for all localizations"
|
||||
lane :update_release_notes do
|
||||
# Path to the release notes file
|
||||
# Make sure to edit it to remove any mention of non-Apple products
|
||||
release_notes_path = "../../release-notes.txt"
|
||||
# Retry logic for fetching or creating the edit version
|
||||
retries = 5
|
||||
begin
|
||||
prepare_version = app.get_edit_app_store_version(platform: Spaceship::ConnectAPI::Platform::IOS)
|
||||
|
||||
# Ensure the release notes file exists
|
||||
# If no "Prepare for Submission" version is found, create a new one
|
||||
if prepare_version.nil?
|
||||
UI.message("No version in 'Prepare for Submission' found. Creating a new version...")
|
||||
latest_version = app.get_latest_version(platform: Spaceship::ConnectAPI::Platform::IOS)
|
||||
new_version_number = (latest_version.version_string.to_f + 0.1).to_s
|
||||
prepare_version = app.create_version!(platform: Spaceship::ConnectAPI::Platform::IOS, version_string: new_version_number)
|
||||
UI.message("Created new version: #{new_version_number}")
|
||||
else
|
||||
UI.message("Found existing version in 'Prepare for Submission': #{prepare_version.version_string}")
|
||||
end
|
||||
rescue => e
|
||||
retries -= 1
|
||||
if retries > 0
|
||||
delay = 20
|
||||
UI.message("Cannot find edit app info... Retrying after #{delay} seconds (remaining: #{retries})")
|
||||
sleep(delay)
|
||||
retry
|
||||
else
|
||||
UI.user_error!("Failed to fetch or create the app version: #{e.message}")
|
||||
end
|
||||
end
|
||||
|
||||
# Extract existing metadata
|
||||
localized_metadata = prepare_version.get_app_store_version_localizations
|
||||
|
||||
# Get all the enabled locales for the app version
|
||||
enabled_locales = localized_metadata.map(&:locale)
|
||||
|
||||
# Define valid language codes and filter them based on enabled locales
|
||||
release_notes_text = options[:release_notes]
|
||||
|
||||
if release_notes_text.nil? || release_notes_text.strip.empty?
|
||||
release_notes_path = "../../release-notes.txt"
|
||||
unless File.exist?(release_notes_path)
|
||||
UI.error("Release notes file does not exist at path: #{release_notes_path}")
|
||||
next # Skip the rest of the lane if file not found
|
||||
UI.user_error!("No release notes provided and no file found. Failing the lane.")
|
||||
end
|
||||
|
||||
|
||||
# Read release notes from file
|
||||
release_notes_text = File.read(release_notes_path)
|
||||
|
||||
# Log the content of release notes
|
||||
UI.message("Release Notes Content:\n#{release_notes_text}")
|
||||
|
||||
# Define version number
|
||||
app_version = get_version_number # Make sure this gets the correct version number
|
||||
UI.message("Version being updated: #{app_version}")
|
||||
|
||||
|
||||
# Hash mapping language codes to release notes text
|
||||
localized_release_notes = {
|
||||
'en-US' => release_notes_text, # English (U.S.) - Primary
|
||||
'ar-SA' => release_notes_text, # Arabic
|
||||
'zh-Hans' => release_notes_text, # Chinese (Simplified)
|
||||
'da' => release_notes_text, # Danish
|
||||
'nl-NL' => release_notes_text, # Dutch
|
||||
'fi' => release_notes_text, # Finnish
|
||||
'fr-FR' => release_notes_text, # French
|
||||
'de-DE' => release_notes_text, # German
|
||||
'he' => release_notes_text, # Hebrew
|
||||
'hu' => release_notes_text, # Hungarian
|
||||
'it' => release_notes_text, # Italian
|
||||
'pt-BR' => release_notes_text, # Portuguese (Brazil)
|
||||
'pt-PT' => release_notes_text, # Portuguese (Portugal)
|
||||
'ro' => release_notes_text, # Romanian
|
||||
'ru' => release_notes_text, # Russian
|
||||
'es-MX' => release_notes_text, # Spanish (Mexico)
|
||||
'es-ES' => release_notes_text, # Spanish (Spain)
|
||||
'sv' => release_notes_text, # Swedish
|
||||
}
|
||||
|
||||
# Log which version and what content is being set
|
||||
localized_release_notes.each do |locale, notes|
|
||||
UI.message("Setting release notes for #{locale}:\n#{notes}\n")
|
||||
end
|
||||
|
||||
# Update release notes in App Store Connect for all localizations
|
||||
deliver(
|
||||
app_identifier: app_identifiers.first, # Use the first app identifier
|
||||
app_version: app_version, # Use the fetched app version
|
||||
skip_metadata: true, # We are updating metadata
|
||||
skip_screenshots: true,
|
||||
skip_binary_upload: true,
|
||||
force: true, # Skip HTML report verification
|
||||
release_notes: localized_release_notes,
|
||||
submit_for_review: false, # Change this to true if you want to automatically submit the version for review
|
||||
automatic_release: false # Change to true if you want the version to be released automatically once approved
|
||||
)
|
||||
end
|
||||
|
||||
localized_release_notes = {
|
||||
'en-US' => release_notes_text, # English (U.S.) - Primary
|
||||
'ar-SA' => release_notes_text, # Arabic
|
||||
'zh-Hans' => release_notes_text, # Chinese (Simplified)
|
||||
'hr' => release_notes_text, # Croatian
|
||||
'da' => release_notes_text, # Danish
|
||||
'nl-NL' => release_notes_text, # Dutch
|
||||
'fi' => release_notes_text, # Finnish
|
||||
'fr-FR' => release_notes_text, # French
|
||||
'de-DE' => release_notes_text, # German
|
||||
'el' => release_notes_text, # Greek
|
||||
'he' => release_notes_text, # Hebrew
|
||||
'hu' => release_notes_text, # Hungarian
|
||||
'it' => release_notes_text, # Italian
|
||||
'ja' => release_notes_text, # Japanese
|
||||
'ms' => release_notes_text, # Malay
|
||||
'nb-NO' => release_notes_text, # Norwegian
|
||||
'pl' => release_notes_text, # Polish
|
||||
'pt-BR' => release_notes_text, # Portuguese (Brazil)
|
||||
'pt-PT' => release_notes_text, # Portuguese (Portugal)
|
||||
'ro' => release_notes_text, # Romanian
|
||||
'ru' => release_notes_text, # Russian
|
||||
'es-MX' => release_notes_text, # Spanish (Mexico)
|
||||
'es-ES' => release_notes_text, # Spanish (Spain)
|
||||
'sv' => release_notes_text, # Swedish
|
||||
'th' => release_notes_text, # Thai
|
||||
}.select { |locale, _| enabled_locales.include?(locale) } # Only include enabled locales
|
||||
|
||||
# Review what's going to be updated
|
||||
UI.message("Review the following release notes updates:")
|
||||
localized_release_notes.each do |locale, notes|
|
||||
UI.message("Locale: #{locale} - Notes: #{notes}")
|
||||
end
|
||||
|
||||
unless options[:force_yes]
|
||||
confirm = UI.confirm("Do you want to proceed with these release notes updates?")
|
||||
unless confirm
|
||||
UI.user_error!("User aborted the lane.")
|
||||
end
|
||||
end
|
||||
|
||||
# Update release notes in App Store Connect and skip all other metadata
|
||||
localized_release_notes.each do |locale, notes|
|
||||
app_store_version_localization = localized_metadata.find { |loc| loc.locale == locale }
|
||||
|
||||
if app_store_version_localization
|
||||
app_store_version_localization.update(attributes: { "whats_new" => notes })
|
||||
else
|
||||
UI.error("No localization found for locale #{locale}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
36
loc/pl.json
36
loc/pl.json
@ -77,15 +77,11 @@
|
||||
"wasnt_paid_and_expired": "Ta faktura nie została opłacona i przeterminowała się."
|
||||
},
|
||||
"plausibledeniability": {
|
||||
"create_fake_storage": "Utwórz szyfrowany schowek",
|
||||
"create_password": "Utwórz hasło",
|
||||
"create_password_explanation": "Hasło portfela widmo, powinno różnić się od głównego hasła.",
|
||||
"help": "W pewnych okolicznościach możesz być zmuszony do podania hasła. Aby chronić swoje środki w portfelu głównym, BlueWallet może stworzyć dodatkową szyfrowaną przestrzeń z innym hasłem. Będąc do tego zmuszonym przez trzecią stronę, możesz je ujawnić. Po jego wpisaniu BlueWallet odblokuje nowy portfel \"widmo\". Będzie on wyglądał na prawdziwy i pozwoli nie ujawniać zawartości głównego.",
|
||||
"help2": "Nowa przestrzeń będzie w pełni funkcjonalna i możesz przechowywać w niej minimalne ilości, aby wyglądało to wiarygodnie.",
|
||||
"create_fake_storage": "Utwórz zaszyfrowany magazyn danych",
|
||||
"create_password_explanation": "Hasło fałszywego magazynu danych, powinno różnić się od głównego.",
|
||||
"help": "W pewnych okolicznościach możesz być zmuszony do podania hasła. Aby chronić swoje środki w portfelu głównym, BlueWallet może stworzyć dodatkowy, zaszyfrowany magazyn danych z innym hasłem. W przypadku nacisku ze strony trzeciej możesz ujawnić to alternatywne hasło. Po jego wpisaniu BlueWallet odblokuje nowy, fałszywy portfel. Będzie on wyglądał na prawdziwy i pozwoli ukryć zawartość portfela głównego.",
|
||||
"help2": "Nowy magazyn danych będzie w pełni funkcjonalny i możesz przechowywać w niej minimalne ilości, aby wyglądało to wiarygodnie.",
|
||||
"password_should_not_match": "Hasło jest aktualnie w użyciu. Spróbuj z innym hasłem.",
|
||||
"passwords_do_not_match": "Hasła do siebie nie pasują, spróbuj ponownie.",
|
||||
"confirm_password": "Wpisz ponownie hasło",
|
||||
"success": "Sukces",
|
||||
"title": "Wiarygodna zaprzeczalność"
|
||||
},
|
||||
"pleasebackup": {
|
||||
@ -221,6 +217,8 @@
|
||||
"about_sm_discord": "Serwer Discord",
|
||||
"about_sm_telegram": "Chat na Telegramie",
|
||||
"about_sm_twitter": "Obserwuj nas na Twitterze",
|
||||
"privacy_temporary_screenshots": "Zezwól na zrzuty ekranu",
|
||||
"privacy_temporary_screenshots_instructions": "Ochrona przed przechwytywaniem ekranu zostanie wyłączona na tę sesję, co pozwoli na robienie zrzutów ekranu. Po zamknięciu i ponownym otwarciu aplikacji, ochrona zostanie automatycznie włączona ponownie.",
|
||||
"advanced_options": "Opcje Zaawansowane",
|
||||
"biometrics": "Biometria",
|
||||
"biometrics_no_longer_available": "Ustawienia twojego urządzenia zostały zmienione i nie są już zgodne z wybranymi ustawieniami bezpieczeństwa w aplikacji. Proszę ponownie włączyć biometrię lub kod dostępu, a następnie uruchomić ponownie aplikację, aby zastosować te zmiany.",
|
||||
@ -260,14 +258,18 @@
|
||||
"electrum_history": "Historia serwerów",
|
||||
"electrum_reset_to_default": "Czy na pewno ustawić domyślne ustawienia Electrum?",
|
||||
"electrum_clear": "Wyczyść",
|
||||
"encrypt_decrypt": "Odszyfruj Schowek",
|
||||
"encrypt_decrypt": "Odszyfruj Magazyn Danych",
|
||||
"encrypt_decrypt_q": "Czy jesteś pewien, że chcesz odszyfrować schowek? To pozwoli na dostęp do twoich portfeli bez hasła.",
|
||||
"encrypt_enc_and_pass": "Szyfrowany i chroniony hasłem",
|
||||
"encrypt_storage_explanation_headline": "Włącz szyfrowanie danych",
|
||||
"encrypt_storage_explanation_description_line1": "Włączenie szyfrowania danych dodaje dodatkową warstwę ochrony do aplikacji, zabezpieczając sposób, w jaki dane są przechowywane na urządzeniu. Utrudnia to dostęp do Twoich informacji bez odpowiedniego upoważnienia.",
|
||||
"encrypt_storage_explanation_description_line2": "Jednak warto wiedzieć, że to szyfrowanie chroni jedynie dostęp do portfeli przechowywanych w pęku kluczy urządzenia. Nie zabezpiecza ono samych portfeli hasłem ani żadną dodatkową ochroną.",
|
||||
"i_understand": "Rozumiem",
|
||||
"encrypt_title": "Zabezpieczenia",
|
||||
"encrypt_tstorage": "Schowek",
|
||||
"encrypt_tstorage": "Dane",
|
||||
"encrypt_use": "Użyj {type}",
|
||||
"encrypted_feature_disabled": "Ta funkcja nie może być używana z włączonym szyfrowaniem pamięci.",
|
||||
"encrypt_use_expl": "{type} będzie użyty w celu potwierdzenia twojej tożsamości przed wykonaniem transakcji, odblokowaniem, eksportem lub usunięciem portfela. {type} nie będzie użyty do odblokowanie danych zaszyfrowanych.",
|
||||
"encrypt_use_expl": "{type} będzie użyty w celu potwierdzenia twojej tożsamości przed wykonaniem transakcji, odblokowaniem, eksportem lub usunięciem portfela. {type} nie będzie użyty do odblokowania danych zaszyfrowanych.",
|
||||
"biometrics_fail": "Jeśli {type} nie jest włączony lub nie udaje się odblokować, możesz alternatywnie użyć kodu dostępu swojego urządzenia.",
|
||||
"general": "Ogólne",
|
||||
"general_adv_mode": "Tryb zaawansowany",
|
||||
@ -291,8 +293,7 @@
|
||||
"notifications": "Powiadomienia",
|
||||
"open_link_in_explorer": "Otwórz link w eksploratorze bloków",
|
||||
"password": "Hasło",
|
||||
"password_explain": "Stwórz hasło które odszyfruje schowek",
|
||||
"passwords_do_not_match": "Hasła się nie zgadzają",
|
||||
"password_explain": "Podaj hasło, do odblokowania pamięci telefonu.",
|
||||
"plausible_deniability": "Wiarygodna zaprzeczalność",
|
||||
"privacy": "Prywatność",
|
||||
"privacy_read_clipboard": "Czytaj Schowek",
|
||||
@ -304,7 +305,6 @@
|
||||
"privacy_do_not_track_explanation": "Informacje dotyczące wydajności i niezawodności nie będą przesyłane do analizy.",
|
||||
"push_notifications": "Powiadomienia Push",
|
||||
"rate": "Kurs",
|
||||
"confirm_password": "Wprowadź Ponownie hasło",
|
||||
"selfTest": "Autotest",
|
||||
"save": "Zapisz",
|
||||
"saved": "Zapisano",
|
||||
@ -380,6 +380,7 @@
|
||||
"add_bitcoin": "Bitcoin",
|
||||
"add_bitcoin_explain": "Prosty i potężny portfel Bitcoin",
|
||||
"add_create": "Utwórz",
|
||||
"total_balance": "Saldo całkowite",
|
||||
"add_entropy": "Entropia",
|
||||
"add_entropy_bytes": "{bytes} bajtów entropii",
|
||||
"add_entropy_generated": "{gen} bajtów wygenerowanej entropii",
|
||||
@ -480,6 +481,13 @@
|
||||
"xpub_title": "XPUB portfela",
|
||||
"manage_wallets_search_placeholder": "Szukaj portfeli, notatek"
|
||||
},
|
||||
"total_balance_view": {
|
||||
"view_in_bitcoin": "Pokaż w Bitcoinach",
|
||||
"view_in_sats": "Pokaż w satsach",
|
||||
"view_in_fiat": "Pokaż w {currency}",
|
||||
"title": "Saldo całkowite",
|
||||
"explanation": "Wyświetl saldo całkowite wszystkich swoich portfeli na ekranie podglądu."
|
||||
},
|
||||
"multisig": {
|
||||
"multisig_vault": "Skarbiec",
|
||||
"default_label": "Skarbiec wielopodpisowy",
|
||||
|
@ -83,7 +83,7 @@ const DetailViewStackScreensStack = () => {
|
||||
const RightBarButtons = useMemo(
|
||||
() => (
|
||||
<>
|
||||
<PlusIcon accessibilityRole="button" accessibilityLabel={loc.wallets.add_title} onPress={navigateToAddWallet} />
|
||||
<PlusIcon onPress={navigateToAddWallet} />
|
||||
<View style={styles.width24} />
|
||||
<SettingsButton />
|
||||
</>
|
||||
@ -380,10 +380,10 @@ const DetailViewStackScreensStack = () => {
|
||||
component={ManageWallets}
|
||||
options={navigationStyle({
|
||||
headerBackVisible: false,
|
||||
headerLargeTitle: true,
|
||||
gestureEnabled: false,
|
||||
presentation: 'modal',
|
||||
presentation: 'containedModal',
|
||||
title: loc.wallets.manage_title,
|
||||
statusBarStyle: 'auto',
|
||||
})(theme)}
|
||||
/>
|
||||
</DetailViewStack.Navigator>
|
||||
|
900
package-lock.json
generated
900
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
30
package.json
30
package.json
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "bluewallet",
|
||||
"version": "7.0.3",
|
||||
"version": "7.0.4",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@ -10,11 +10,11 @@
|
||||
"@babel/core": "^7.20.0",
|
||||
"@babel/runtime": "^7.20.0",
|
||||
"@jest/reporters": "^27.5.1",
|
||||
"@react-native/babel-preset": "^0.74.87",
|
||||
"@react-native/eslint-config": "^0.74.87",
|
||||
"@react-native/js-polyfills": "^0.74.87",
|
||||
"@react-native/metro-babel-transformer": "^0.74.87",
|
||||
"@react-native/typescript-config": "^0.74.87",
|
||||
"@react-native/babel-preset": "^0.75.2",
|
||||
"@react-native/eslint-config": "^0.75.2",
|
||||
"@react-native/js-polyfills": "^0.75.2",
|
||||
"@react-native/metro-babel-transformer": "^0.75.2",
|
||||
"@react-native/typescript-config": "^0.75.2",
|
||||
"@types/bip38": "^3.1.2",
|
||||
"@types/bs58check": "^2.1.0",
|
||||
"@types/create-hash": "^1.2.2",
|
||||
@ -75,7 +75,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/preset-env": "7.25.3",
|
||||
"@bugsnag/react-native": "7.25.0",
|
||||
"@bugsnag/react-native": "7.25.1",
|
||||
"@bugsnag/source-maps": "2.3.3",
|
||||
"@keystonehq/bc-ur-registry": "0.7.0",
|
||||
"@lodev09/react-native-true-sheet": "github:BlueWallet/react-native-true-sheet#839f2966cee77c0ad99d09609dadb61a338e7f54",
|
||||
@ -85,7 +85,7 @@
|
||||
"@react-native-clipboard/clipboard": "1.14.1",
|
||||
"@react-native-community/push-notification-ios": "1.11.0",
|
||||
"@react-native-menu/menu": "https://github.com/BlueWallet/menu.git#958fac3d40811f38b53042ada9168175e321b99f",
|
||||
"@react-native/gradle-plugin": "^0.74.85",
|
||||
"@react-native/gradle-plugin": "^0.75.2",
|
||||
"@react-navigation/drawer": "6.7.2",
|
||||
"@react-navigation/native": "6.1.18",
|
||||
"@react-navigation/native-stack": "6.11.0",
|
||||
@ -98,7 +98,7 @@
|
||||
"base-x": "4.0.0",
|
||||
"bc-bech32": "file:blue_modules/bc-bech32",
|
||||
"bech32": "2.0.0",
|
||||
"bignumber.js": "9.1.1",
|
||||
"bignumber.js": "9.1.2",
|
||||
"bip21": "2.0.3",
|
||||
"bip32": "3.0.1",
|
||||
"bip38": "github:BlueWallet/bip38",
|
||||
@ -110,7 +110,7 @@
|
||||
"coinselect": "3.1.13",
|
||||
"crypto-js": "4.2.0",
|
||||
"dayjs": "1.11.13",
|
||||
"detox": "20.25.5",
|
||||
"detox": "20.25.6",
|
||||
"ecpair": "2.0.1",
|
||||
"ecurve": "1.0.6",
|
||||
"electrum-client": "github:BlueWallet/rn-electrum-client#1bfe3cc",
|
||||
@ -124,7 +124,7 @@
|
||||
"prop-types": "15.8.1",
|
||||
"react": "18.3.1",
|
||||
"react-localization": "github:BlueWallet/react-localization#ae7969a",
|
||||
"react-native": "0.74.5",
|
||||
"react-native": "0.75.2",
|
||||
"react-native-biometrics": "3.0.1",
|
||||
"react-native-blue-crypto": "github:BlueWallet/react-native-blue-crypto#3cb5442",
|
||||
"react-native-camera-kit": "13.0.0",
|
||||
@ -132,9 +132,9 @@
|
||||
"react-native-default-preference": "1.4.4",
|
||||
"react-native-device-info": "11.1.0",
|
||||
"react-native-document-picker": "9.3.1",
|
||||
"react-native-draggable-flatlist": "github:BlueWallet/react-native-draggable-flatlist#v4.0.1",
|
||||
"react-native-draggable-flatlist": "github:BlueWallet/react-native-draggable-flatlist#3a61627",
|
||||
"react-native-fs": "2.20.0",
|
||||
"react-native-gesture-handler": "2.18.1",
|
||||
"react-native-gesture-handler": "2.19.0",
|
||||
"react-native-handoff": "github:BlueWallet/react-native-handoff#v0.0.4",
|
||||
"react-native-haptic-feedback": "2.3.1",
|
||||
"react-native-idle-timer": "github:BlueWallet/react-native-idle-timer#v2.2.3",
|
||||
@ -152,8 +152,8 @@
|
||||
"react-native-quick-actions": "0.3.13",
|
||||
"react-native-randombytes": "3.6.1",
|
||||
"react-native-rate": "1.2.12",
|
||||
"react-native-reanimated": "3.15.0",
|
||||
"@react-native/metro-config": "0.74.87",
|
||||
"react-native-reanimated": "3.15.1",
|
||||
"@react-native/metro-config": "0.75.2",
|
||||
"react-native-safe-area-context": "4.10.9",
|
||||
"react-native-screens": "3.34.0",
|
||||
"react-native-secure-key-store": "github:BlueWallet/react-native-secure-key-store#2076b4849e88aa0a78e08bfbb4ce3923e0925cbc",
|
||||
|
@ -33,7 +33,7 @@ const styles = StyleSheet.create({
|
||||
justifyContent: 'center',
|
||||
borderRadius: 20,
|
||||
position: 'absolute',
|
||||
right: 16,
|
||||
left: 16,
|
||||
top: 44,
|
||||
},
|
||||
closeImage: {
|
||||
@ -342,7 +342,14 @@ const ScanQRCode = () => {
|
||||
<Button title={loc.send.open_settings} onPress={openPrivacyDesktopSettings} />
|
||||
</View>
|
||||
) : isFocused ? (
|
||||
<CameraScreen scanBarcode onReadCode={event => onBarCodeRead({ data: event?.nativeEvent?.codeStringValue })} showFrame={false} />
|
||||
<CameraScreen
|
||||
scanBarcode
|
||||
torchOffImage={require('../../img/flash-off.png')}
|
||||
torchOnImage={require('../../img/flash-on.png')}
|
||||
cameraFlipImage={require('../../img/camera-rotate-solid.png')}
|
||||
onReadCode={event => onBarCodeRead({ data: event?.nativeEvent?.codeStringValue })}
|
||||
showFrame={false}
|
||||
/>
|
||||
) : null}
|
||||
<TouchableOpacity accessibilityRole="button" accessibilityLabel={loc._.close} style={styles.closeTouch} onPress={dismiss}>
|
||||
<Image style={styles.closeImage} source={require('../../img/close-white.png')} />
|
||||
|
@ -1,8 +1,8 @@
|
||||
import React, { useCallback, useEffect, useReducer, useRef } from 'react';
|
||||
import { Alert, Platform, ScrollView, StyleSheet, Text, TouchableOpacity, TouchableWithoutFeedback, View } from 'react-native';
|
||||
import { Alert, Platform, ScrollView, StyleSheet, Text, TouchableWithoutFeedback, View } from 'react-native';
|
||||
import { BlueCard, BlueSpacing20, BlueText } from '../../BlueComponents';
|
||||
import presentAlert from '../../components/Alert';
|
||||
import ListItem from '../../components/ListItem';
|
||||
import ListItem, { TouchableOpacityWrapper } from '../../components/ListItem';
|
||||
import { useTheme } from '../../components/themes';
|
||||
import { unlockWithBiometrics, useBiometrics } from '../../hooks/useBiometrics';
|
||||
import loc from '../../loc';
|
||||
@ -195,7 +195,7 @@ const EncryptStorage = () => {
|
||||
title={loc.settings.plausible_deniability}
|
||||
chevron
|
||||
testID="PlausibleDeniabilityButton"
|
||||
Component={TouchableOpacity}
|
||||
Component={TouchableOpacityWrapper}
|
||||
containerStyle={[styles.row, styleHooks.root]}
|
||||
/>
|
||||
)}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { DrawerContentScrollView } from '@react-navigation/drawer';
|
||||
import { NavigationProp, ParamListBase, useIsFocused } from '@react-navigation/native';
|
||||
import React, { memo, useCallback, useEffect, useMemo, useReducer, useRef } from 'react';
|
||||
import { InteractionManager, LayoutAnimation, StyleSheet, ViewStyle } from 'react-native';
|
||||
import { InteractionManager, LayoutAnimation, StyleSheet, View, ViewStyle } from 'react-native';
|
||||
|
||||
import triggerHapticFeedback, { HapticFeedbackTypes } from '../../blue_modules/hapticFeedback';
|
||||
import { TWallet } from '../../class/wallets/types';
|
||||
@ -146,7 +146,11 @@ const DrawerList: React.FC<DrawerListProps> = memo(({ navigation }) => {
|
||||
showsVerticalScrollIndicator={false}
|
||||
>
|
||||
<Header leftText={loc.wallets.list_title} onNewWalletPress={onNewWalletPress} isDrawerList />
|
||||
{isTotalBalanceEnabled && <TotalWalletsBalance />}
|
||||
{isTotalBalanceEnabled && (
|
||||
<View style={stylesHook.root}>
|
||||
<TotalWalletsBalance />
|
||||
</View>
|
||||
)}
|
||||
<WalletsCarousel
|
||||
data={state.wallets}
|
||||
extraData={[state.wallets]}
|
||||
|
@ -1,20 +1,29 @@
|
||||
import React, { useEffect, useLayoutEffect, useRef, useReducer, useCallback, useMemo } from 'react';
|
||||
import { Platform, StyleSheet, useColorScheme, TouchableOpacity, Image, Animated, Text, I18nManager } from 'react-native';
|
||||
// @ts-ignore: no declaration file
|
||||
import DraggableFlatList, { ScaleDecorator } from 'react-native-draggable-flatlist';
|
||||
import React, { useEffect, useLayoutEffect, useReducer, useCallback, useMemo, useRef } from 'react';
|
||||
import { StyleSheet, TouchableOpacity, Image, Text, Alert, I18nManager, Animated, LayoutAnimation } from 'react-native';
|
||||
import {
|
||||
NestableScrollContainer,
|
||||
ScaleDecorator,
|
||||
OpacityDecorator,
|
||||
NestableDraggableFlatList,
|
||||
RenderItem,
|
||||
// @ts-expect-error: react-native-draggable-flatlist is not typed
|
||||
} from 'react-native-draggable-flatlist';
|
||||
import { GestureHandlerRootView } from 'react-native-gesture-handler';
|
||||
import { useFocusEffect, useNavigation } from '@react-navigation/native';
|
||||
import triggerHapticFeedback, { HapticFeedbackTypes } from '../../blue_modules/hapticFeedback';
|
||||
import { useTheme } from '../../components/themes';
|
||||
import { WalletCarouselItem } from '../../components/WalletsCarousel';
|
||||
import { TransactionListItem } from '../../components/TransactionListItem';
|
||||
import { useExtendedNavigation } from '../../hooks/useExtendedNavigation';
|
||||
import loc from '../../loc';
|
||||
import { useStorage } from '../../hooks/context/useStorage';
|
||||
import useDebounce from '../../hooks/useDebounce';
|
||||
import { TTXMetadata } from '../../class';
|
||||
import { ExtendedTransaction, LightningTransaction, Transaction, TWallet } from '../../class/wallets/types';
|
||||
import { BitcoinUnit } from '../../models/bitcoinUnits';
|
||||
import useBounceAnimation from '../../hooks/useBounceAnimation';
|
||||
import { unlockWithBiometrics, useBiometrics } from '../../hooks/useBiometrics';
|
||||
import presentAlert from '../../components/Alert';
|
||||
import prompt from '../../helpers/prompt';
|
||||
import HeaderRightButton from '../../components/HeaderRightButton';
|
||||
import { ManageWalletsListItem } from '../../components/ManageWalletsListItem';
|
||||
|
||||
enum ItemType {
|
||||
WalletSection = 'wallet',
|
||||
@ -35,9 +44,16 @@ type Item = WalletItem | TransactionItem;
|
||||
|
||||
const SET_SEARCH_QUERY = 'SET_SEARCH_QUERY';
|
||||
const SET_IS_SEARCH_FOCUSED = 'SET_IS_SEARCH_FOCUSED';
|
||||
const SET_WALLET_DATA = 'SET_WALLET_DATA';
|
||||
const SET_TX_METADATA = 'SET_TX_METADATA';
|
||||
const SET_ORDER = 'SET_ORDER';
|
||||
const SET_INITIAL_ORDER = 'SET_INITIAL_ORDER';
|
||||
const SET_FILTERED_ORDER = 'SET_FILTERED_ORDER';
|
||||
const SET_TEMP_ORDER = 'SET_TEMP_ORDER';
|
||||
const REMOVE_WALLET = 'REMOVE_WALLET';
|
||||
const SAVE_CHANGES = 'SAVE_CHANGES';
|
||||
|
||||
interface SaveChangesAction {
|
||||
type: typeof SAVE_CHANGES;
|
||||
payload: TWallet[];
|
||||
}
|
||||
|
||||
interface SetSearchQueryAction {
|
||||
type: typeof SET_SEARCH_QUERY;
|
||||
@ -49,37 +65,55 @@ interface SetIsSearchFocusedAction {
|
||||
payload: boolean;
|
||||
}
|
||||
|
||||
interface SetWalletDataAction {
|
||||
type: typeof SET_WALLET_DATA;
|
||||
payload: TWallet[];
|
||||
interface SetInitialOrderAction {
|
||||
type: typeof SET_INITIAL_ORDER;
|
||||
payload: { wallets: TWallet[]; txMetadata: TTXMetadata };
|
||||
}
|
||||
|
||||
interface SetTxMetadataAction {
|
||||
type: typeof SET_TX_METADATA;
|
||||
payload: TTXMetadata;
|
||||
interface SetFilteredOrderAction {
|
||||
type: typeof SET_FILTERED_ORDER;
|
||||
payload: string;
|
||||
}
|
||||
|
||||
interface SetOrderAction {
|
||||
type: typeof SET_ORDER;
|
||||
interface SetTempOrderAction {
|
||||
type: typeof SET_TEMP_ORDER;
|
||||
payload: Item[];
|
||||
}
|
||||
|
||||
type Action = SetSearchQueryAction | SetIsSearchFocusedAction | SetWalletDataAction | SetTxMetadataAction | SetOrderAction;
|
||||
interface RemoveWalletAction {
|
||||
type: typeof REMOVE_WALLET;
|
||||
payload: string; // Wallet ID
|
||||
}
|
||||
|
||||
type Action =
|
||||
| SetSearchQueryAction
|
||||
| SetIsSearchFocusedAction
|
||||
| SetInitialOrderAction
|
||||
| SetFilteredOrderAction
|
||||
| SetTempOrderAction
|
||||
| SaveChangesAction
|
||||
| RemoveWalletAction;
|
||||
|
||||
interface State {
|
||||
searchQuery: string;
|
||||
isSearchFocused: boolean;
|
||||
walletData: TWallet[];
|
||||
txMetadata: TTXMetadata;
|
||||
order: Item[];
|
||||
tempOrder: Item[];
|
||||
wallets: TWallet[];
|
||||
txMetadata: TTXMetadata;
|
||||
}
|
||||
|
||||
const initialState: State = {
|
||||
searchQuery: '',
|
||||
isSearchFocused: false,
|
||||
walletData: [],
|
||||
txMetadata: {},
|
||||
order: [],
|
||||
tempOrder: [],
|
||||
wallets: [],
|
||||
txMetadata: {},
|
||||
};
|
||||
|
||||
const deepCopyWallets = (wallets: TWallet[]): TWallet[] => {
|
||||
return wallets.map(wallet => Object.assign(Object.create(Object.getPrototypeOf(wallet)), wallet));
|
||||
};
|
||||
|
||||
const reducer = (state: State, action: Action): State => {
|
||||
@ -88,122 +122,293 @@ const reducer = (state: State, action: Action): State => {
|
||||
return { ...state, searchQuery: action.payload };
|
||||
case SET_IS_SEARCH_FOCUSED:
|
||||
return { ...state, isSearchFocused: action.payload };
|
||||
case SET_WALLET_DATA:
|
||||
return { ...state, walletData: action.payload };
|
||||
case SET_TX_METADATA:
|
||||
return { ...state, txMetadata: action.payload };
|
||||
case SET_ORDER:
|
||||
return { ...state, order: action.payload };
|
||||
case SET_INITIAL_ORDER: {
|
||||
const initialWalletsOrder: WalletItem[] = deepCopyWallets(action.payload.wallets).map(wallet => ({
|
||||
type: ItemType.WalletSection,
|
||||
data: wallet,
|
||||
}));
|
||||
return {
|
||||
...state,
|
||||
wallets: action.payload.wallets,
|
||||
txMetadata: action.payload.txMetadata,
|
||||
order: initialWalletsOrder,
|
||||
tempOrder: initialWalletsOrder,
|
||||
};
|
||||
}
|
||||
case SET_FILTERED_ORDER: {
|
||||
const query = action.payload.toLowerCase();
|
||||
const filteredWallets = state.wallets
|
||||
.filter(wallet => wallet.getLabel()?.toLowerCase().includes(query))
|
||||
.map(wallet => ({ type: ItemType.WalletSection, data: wallet }));
|
||||
|
||||
const filteredTxMetadata = Object.entries(state.txMetadata).filter(([_, tx]) => tx.memo?.toLowerCase().includes(query));
|
||||
|
||||
const filteredTransactions = state.wallets.flatMap(wallet =>
|
||||
wallet
|
||||
.getTransactions()
|
||||
.filter((tx: Transaction) =>
|
||||
filteredTxMetadata.some(([txid, txMeta]) => tx.hash === txid && txMeta.memo?.toLowerCase().includes(query)),
|
||||
)
|
||||
.map((tx: Transaction) => ({ type: ItemType.TransactionSection, data: tx as ExtendedTransaction & LightningTransaction })),
|
||||
);
|
||||
|
||||
const filteredOrder = [...filteredWallets, ...filteredTransactions];
|
||||
|
||||
return {
|
||||
...state,
|
||||
tempOrder: filteredOrder,
|
||||
};
|
||||
}
|
||||
case SAVE_CHANGES: {
|
||||
return {
|
||||
...state,
|
||||
wallets: deepCopyWallets(action.payload),
|
||||
tempOrder: state.tempOrder.map(item =>
|
||||
item.type === ItemType.WalletSection
|
||||
? { ...item, data: action.payload.find(wallet => wallet.getID() === item.data.getID())! }
|
||||
: item,
|
||||
),
|
||||
};
|
||||
}
|
||||
case SET_TEMP_ORDER: {
|
||||
return { ...state, tempOrder: action.payload };
|
||||
}
|
||||
case REMOVE_WALLET: {
|
||||
const updatedOrder = state.tempOrder.filter(item => item.type !== ItemType.WalletSection || item.data.getID() !== action.payload);
|
||||
return {
|
||||
...state,
|
||||
tempOrder: updatedOrder,
|
||||
};
|
||||
}
|
||||
default:
|
||||
return state;
|
||||
throw new Error(`Unhandled action type: ${(action as Action).type}`);
|
||||
}
|
||||
};
|
||||
|
||||
const ManageWallets: React.FC = () => {
|
||||
const sortableList = useRef(null);
|
||||
const { colors, closeImage } = useTheme();
|
||||
const { wallets, setWalletsWithNewOrder, txMetadata } = useStorage();
|
||||
const colorScheme = useColorScheme();
|
||||
const { wallets: storedWallets, setWalletsWithNewOrder, txMetadata } = useStorage();
|
||||
const walletsRef = useRef<TWallet[]>(deepCopyWallets(storedWallets)); // Create a deep copy of wallets for the DraggableFlatList
|
||||
const { navigate, setOptions, goBack } = useExtendedNavigation();
|
||||
const [state, dispatch] = useReducer(reducer, initialState);
|
||||
|
||||
const { isBiometricUseCapableAndEnabled } = useBiometrics();
|
||||
const navigation = useNavigation();
|
||||
const debouncedSearchQuery = useDebounce(state.searchQuery, 300);
|
||||
const bounceAnim = useBounceAnimation(state.searchQuery);
|
||||
const beforeRemoveListenerRef = useRef<(() => void) | null>(null);
|
||||
const stylesHook = {
|
||||
root: {
|
||||
backgroundColor: colors.elevated,
|
||||
},
|
||||
tip: {
|
||||
backgroundColor: colors.ballOutgoingExpired,
|
||||
},
|
||||
noResultsText: {
|
||||
color: colors.foregroundColor,
|
||||
},
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const initialOrder: Item[] = wallets.map(wallet => ({ type: ItemType.WalletSection, data: wallet }));
|
||||
dispatch({ type: SET_WALLET_DATA, payload: wallets });
|
||||
dispatch({ type: SET_TX_METADATA, payload: txMetadata });
|
||||
dispatch({ type: SET_ORDER, payload: initialOrder });
|
||||
}, [wallets, txMetadata]);
|
||||
dispatch({
|
||||
type: SET_INITIAL_ORDER,
|
||||
payload: { wallets: walletsRef.current, txMetadata },
|
||||
});
|
||||
}, [txMetadata]);
|
||||
|
||||
useEffect(() => {
|
||||
if (debouncedSearchQuery) {
|
||||
dispatch({ type: SET_FILTERED_ORDER, payload: debouncedSearchQuery });
|
||||
} else {
|
||||
dispatch({ type: SET_INITIAL_ORDER, payload: { wallets: walletsRef.current, txMetadata } });
|
||||
}
|
||||
}, [debouncedSearchQuery, txMetadata]);
|
||||
|
||||
const handleClose = useCallback(() => {
|
||||
// Filter out only wallet items from the order array
|
||||
const walletOrder = state.order.filter((item): item is WalletItem => item.type === ItemType.WalletSection).map(item => item.data);
|
||||
if (state.searchQuery.length === 0 && !state.isSearchFocused) {
|
||||
const newWalletOrder = state.tempOrder
|
||||
.filter((item): item is WalletItem => item.type === ItemType.WalletSection)
|
||||
.map(item => item.data);
|
||||
|
||||
setWalletsWithNewOrder(walletOrder);
|
||||
goBack();
|
||||
}, [goBack, setWalletsWithNewOrder, state.order]);
|
||||
setWalletsWithNewOrder(newWalletOrder);
|
||||
|
||||
const HeaderRightButton = useMemo(
|
||||
dispatch({ type: SAVE_CHANGES, payload: newWalletOrder });
|
||||
|
||||
walletsRef.current = deepCopyWallets(newWalletOrder);
|
||||
|
||||
if (beforeRemoveListenerRef.current) {
|
||||
navigation.removeListener('beforeRemove', beforeRemoveListenerRef.current);
|
||||
}
|
||||
|
||||
goBack();
|
||||
} else {
|
||||
dispatch({ type: SET_SEARCH_QUERY, payload: '' });
|
||||
dispatch({ type: SET_IS_SEARCH_FOCUSED, payload: false });
|
||||
}
|
||||
}, [goBack, setWalletsWithNewOrder, state.searchQuery, state.isSearchFocused, state.tempOrder, navigation]);
|
||||
const hasUnsavedChanges = useMemo(() => {
|
||||
return JSON.stringify(walletsRef.current) !== JSON.stringify(state.tempOrder.map(item => item.data));
|
||||
}, [state.tempOrder]);
|
||||
|
||||
const HeaderLeftButton = useMemo(
|
||||
() => (
|
||||
<TouchableOpacity
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel={loc._.close}
|
||||
style={styles.button}
|
||||
onPress={handleClose}
|
||||
onPress={goBack}
|
||||
testID="NavigationCloseButton"
|
||||
>
|
||||
<Image source={closeImage} />
|
||||
</TouchableOpacity>
|
||||
),
|
||||
[handleClose, closeImage],
|
||||
[goBack, closeImage],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
setOptions({
|
||||
statusBarStyle: Platform.select({ ios: 'light', default: colorScheme === 'dark' ? 'light' : 'dark' }),
|
||||
headerRight: () => HeaderRightButton,
|
||||
});
|
||||
}, [colorScheme, setOptions, HeaderRightButton]);
|
||||
|
||||
const debouncedSearchQuery = useDebounce(state.searchQuery, 300);
|
||||
|
||||
useEffect(() => {
|
||||
if (debouncedSearchQuery) {
|
||||
const filteredWallets = wallets.filter(wallet => wallet.getLabel()?.toLowerCase().includes(debouncedSearchQuery.toLowerCase()));
|
||||
const filteredTxMetadata = Object.entries(txMetadata).filter(([_, tx]) =>
|
||||
tx.memo?.toLowerCase().includes(debouncedSearchQuery.toLowerCase()),
|
||||
);
|
||||
|
||||
// Filter transactions
|
||||
const filteredTransactions = wallets.flatMap(wallet =>
|
||||
wallet
|
||||
.getTransactions()
|
||||
.filter((tx: Transaction) =>
|
||||
filteredTxMetadata.some(
|
||||
([txid, txMeta]) => tx.hash === txid && txMeta.memo?.toLowerCase().includes(debouncedSearchQuery.toLowerCase()),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
const filteredOrder: Item[] = [
|
||||
...filteredWallets.map(wallet => ({ type: ItemType.WalletSection, data: wallet })),
|
||||
...filteredTransactions.map(tx => ({ type: ItemType.TransactionSection, data: tx })),
|
||||
];
|
||||
|
||||
dispatch({ type: SET_WALLET_DATA, payload: filteredWallets });
|
||||
dispatch({ type: SET_TX_METADATA, payload: Object.fromEntries(filteredTxMetadata) });
|
||||
dispatch({ type: SET_ORDER, payload: filteredOrder });
|
||||
} else {
|
||||
const initialOrder: Item[] = wallets.map(wallet => ({ type: ItemType.WalletSection, data: wallet }));
|
||||
dispatch({ type: SET_WALLET_DATA, payload: wallets });
|
||||
dispatch({ type: SET_TX_METADATA, payload: {} });
|
||||
dispatch({ type: SET_ORDER, payload: initialOrder });
|
||||
}
|
||||
}, [wallets, txMetadata, debouncedSearchQuery]);
|
||||
const SaveButton = useMemo(
|
||||
() => <HeaderRightButton disabled={!hasUnsavedChanges} title={loc.send.input_done} onPress={handleClose} />,
|
||||
[handleClose, hasUnsavedChanges],
|
||||
);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
const searchBarOptions = {
|
||||
hideWhenScrolling: false,
|
||||
onChangeText: (event: { nativeEvent: { text: any } }) => dispatch({ type: SET_SEARCH_QUERY, payload: event.nativeEvent.text }),
|
||||
onClear: () => dispatch({ type: SET_SEARCH_QUERY, payload: '' }),
|
||||
onFocus: () => dispatch({ type: SET_IS_SEARCH_FOCUSED, payload: true }),
|
||||
onBlur: () => dispatch({ type: SET_IS_SEARCH_FOCUSED, payload: false }),
|
||||
placeholder: loc.wallets.manage_wallets_search_placeholder,
|
||||
};
|
||||
|
||||
setOptions({
|
||||
headerSearchBarOptions: {
|
||||
hideWhenScrolling: false,
|
||||
onChangeText: (event: { nativeEvent: { text: any } }) => dispatch({ type: SET_SEARCH_QUERY, payload: event.nativeEvent.text }),
|
||||
onClear: () => dispatch({ type: SET_SEARCH_QUERY, payload: '' }),
|
||||
onFocus: () => dispatch({ type: SET_IS_SEARCH_FOCUSED, payload: true }),
|
||||
onBlur: () => dispatch({ type: SET_IS_SEARCH_FOCUSED, payload: false }),
|
||||
placeholder: loc.wallets.manage_wallets_search_placeholder,
|
||||
},
|
||||
headerLeft: () => HeaderLeftButton,
|
||||
headerRight: () => SaveButton,
|
||||
headerSearchBarOptions: searchBarOptions,
|
||||
});
|
||||
}, [setOptions]);
|
||||
}, [setOptions, HeaderLeftButton, SaveButton]);
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
const beforeRemoveListener = (e: { preventDefault: () => void; data: { action: any } }) => {
|
||||
if (!hasUnsavedChanges) {
|
||||
return;
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
Alert.alert(loc._.discard_changes, loc._.discard_changes_explain, [
|
||||
{ text: loc._.cancel, style: 'cancel', onPress: () => {} },
|
||||
{
|
||||
text: loc._.ok,
|
||||
style: 'default',
|
||||
onPress: () => navigation.dispatch(e.data.action),
|
||||
},
|
||||
]);
|
||||
};
|
||||
|
||||
// @ts-ignore: fix later
|
||||
beforeRemoveListenerRef.current = beforeRemoveListener;
|
||||
|
||||
navigation.addListener('beforeRemove', beforeRemoveListener);
|
||||
|
||||
return () => {
|
||||
if (beforeRemoveListenerRef.current) {
|
||||
navigation.removeListener('beforeRemove', beforeRemoveListenerRef.current);
|
||||
}
|
||||
};
|
||||
}, [hasUnsavedChanges, navigation]),
|
||||
);
|
||||
|
||||
const renderHighlightedText = useCallback(
|
||||
(text: string, query: string) => {
|
||||
const parts = text.split(new RegExp(`(${query})`, 'gi'));
|
||||
return (
|
||||
<Text>
|
||||
{parts.map((part, index) =>
|
||||
query && part.toLowerCase().includes(query.toLowerCase()) ? (
|
||||
<Animated.View key={`${index}-${query}`} style={[styles.highlightedContainer, { transform: [{ scale: bounceAnim }] }]}>
|
||||
<Text style={styles.highlighted}>{part}</Text>
|
||||
</Animated.View>
|
||||
) : (
|
||||
<Text key={`${index}-${query}`} style={query ? styles.dimmedText : styles.defaultText}>
|
||||
{part}
|
||||
</Text>
|
||||
),
|
||||
)}
|
||||
</Text>
|
||||
);
|
||||
},
|
||||
[bounceAnim],
|
||||
);
|
||||
|
||||
const presentWalletHasBalanceAlert = useCallback(async (wallet: TWallet) => {
|
||||
triggerHapticFeedback(HapticFeedbackTypes.NotificationWarning);
|
||||
try {
|
||||
const walletBalanceConfirmation = await prompt(
|
||||
loc.wallets.details_delete_wallet,
|
||||
loc.formatString(loc.wallets.details_del_wb_q, { balance: wallet.getBalance() }),
|
||||
true,
|
||||
'plain-text',
|
||||
true,
|
||||
loc.wallets.details_delete,
|
||||
);
|
||||
if (Number(walletBalanceConfirmation) === wallet.getBalance()) {
|
||||
dispatch({ type: REMOVE_WALLET, payload: wallet.getID() });
|
||||
} else {
|
||||
triggerHapticFeedback(HapticFeedbackTypes.NotificationError);
|
||||
presentAlert({ message: loc.wallets.details_del_wb_err });
|
||||
}
|
||||
} catch (_) {}
|
||||
}, []);
|
||||
|
||||
const handleDeleteWallet = useCallback(
|
||||
async (wallet: TWallet) => {
|
||||
triggerHapticFeedback(HapticFeedbackTypes.NotificationWarning);
|
||||
Alert.alert(
|
||||
loc.wallets.details_delete_wallet,
|
||||
loc.wallets.details_are_you_sure,
|
||||
[
|
||||
{
|
||||
text: loc.wallets.details_yes_delete,
|
||||
onPress: async () => {
|
||||
const isBiometricsEnabled = await isBiometricUseCapableAndEnabled();
|
||||
|
||||
if (isBiometricsEnabled) {
|
||||
if (!(await unlockWithBiometrics())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (wallet.getBalance() > 0 && wallet.allowSend()) {
|
||||
presentWalletHasBalanceAlert(wallet);
|
||||
} else {
|
||||
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
|
||||
dispatch({ type: REMOVE_WALLET, payload: wallet.getID() });
|
||||
}
|
||||
},
|
||||
style: 'destructive',
|
||||
},
|
||||
{ text: loc.wallets.details_no_cancel, onPress: () => {}, style: 'cancel' },
|
||||
],
|
||||
{ cancelable: false },
|
||||
);
|
||||
},
|
||||
[isBiometricUseCapableAndEnabled, presentWalletHasBalanceAlert],
|
||||
);
|
||||
|
||||
const handleToggleHideBalance = useCallback(
|
||||
(wallet: TWallet) => {
|
||||
const updatedOrder = state.tempOrder.map(item => {
|
||||
if (item.type === ItemType.WalletSection && item.data.getID() === wallet.getID()) {
|
||||
item.data.hideBalance = !item.data.hideBalance;
|
||||
return {
|
||||
...item,
|
||||
data: item.data,
|
||||
};
|
||||
}
|
||||
return item;
|
||||
});
|
||||
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
|
||||
|
||||
dispatch({ type: SET_TEMP_ORDER, payload: updatedOrder });
|
||||
},
|
||||
[state.tempOrder],
|
||||
);
|
||||
|
||||
const navigateToWallet = useCallback(
|
||||
(wallet: TWallet) => {
|
||||
@ -216,65 +421,40 @@ const ManageWallets: React.FC = () => {
|
||||
},
|
||||
[goBack, navigate],
|
||||
);
|
||||
|
||||
const isDraggingDisabled = state.searchQuery.length > 0 || state.isSearchFocused;
|
||||
|
||||
const bounceAnim = useBounceAnimation(state.searchQuery);
|
||||
|
||||
const renderHighlightedText = useCallback(
|
||||
(text: string, query: string) => {
|
||||
const parts = text.split(new RegExp(`(${query})`, 'gi'));
|
||||
return (
|
||||
<Text>
|
||||
{parts.map((part, index) =>
|
||||
query && part.toLowerCase().includes(query.toLowerCase()) ? (
|
||||
<Animated.View key={`${index}-${query}`} style={[iStyles.highlightedContainer, { transform: [{ scale: bounceAnim }] }]}>
|
||||
<Text style={iStyles.highlighted}>{part}</Text>
|
||||
</Animated.View>
|
||||
) : (
|
||||
<Text key={`${index}-${query}`} style={query ? iStyles.dimmedText : iStyles.defaultText}>
|
||||
{part}
|
||||
</Text>
|
||||
),
|
||||
)}
|
||||
</Text>
|
||||
);
|
||||
},
|
||||
[bounceAnim],
|
||||
);
|
||||
const renderItem = useCallback(
|
||||
// eslint-disable-next-line react/no-unused-prop-types
|
||||
({ item, drag, isActive }: { item: Item; drag: () => void; isActive: boolean }) => {
|
||||
if (item.type === ItemType.TransactionSection && item.data) {
|
||||
const w = wallets.find(wallet => wallet.getTransactions().some((tx: ExtendedTransaction) => tx.hash === item.data.hash));
|
||||
const walletID = w ? w.getID() : '';
|
||||
return (
|
||||
<TransactionListItem
|
||||
item={item.data}
|
||||
itemPriceUnit={item.data.walletPreferredBalanceUnit || BitcoinUnit.BTC}
|
||||
walletID={walletID}
|
||||
searchQuery={state.searchQuery}
|
||||
const renderWalletItem = useCallback(
|
||||
({ item, drag, isActive }: RenderItem<Item>) => (
|
||||
<ScaleDecorator drag={drag} activeScale={1.1}>
|
||||
<OpacityDecorator activeOpacity={0.5}>
|
||||
<ManageWalletsListItem
|
||||
item={item}
|
||||
isDraggingDisabled={state.searchQuery.length > 0 || state.isSearchFocused}
|
||||
drag={drag}
|
||||
state={state}
|
||||
navigateToWallet={navigateToWallet}
|
||||
renderHighlightedText={renderHighlightedText}
|
||||
handleDeleteWallet={handleDeleteWallet}
|
||||
handleToggleHideBalance={handleToggleHideBalance}
|
||||
/>
|
||||
);
|
||||
} else if (item.type === ItemType.WalletSection) {
|
||||
return (
|
||||
<ScaleDecorator>
|
||||
<WalletCarouselItem
|
||||
item={item.data}
|
||||
handleLongPress={isDraggingDisabled ? undefined : drag}
|
||||
isActive={isActive}
|
||||
onPress={() => navigateToWallet(item.data)}
|
||||
customStyle={styles.padding16}
|
||||
searchQuery={state.searchQuery}
|
||||
renderHighlightedText={renderHighlightedText}
|
||||
/>
|
||||
</ScaleDecorator>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
},
|
||||
[wallets, isDraggingDisabled, navigateToWallet, state.searchQuery, renderHighlightedText],
|
||||
</OpacityDecorator>
|
||||
</ScaleDecorator>
|
||||
),
|
||||
[state, navigateToWallet, renderHighlightedText, handleDeleteWallet, handleToggleHideBalance],
|
||||
);
|
||||
|
||||
const renderPlaceholder = useCallback(
|
||||
({ item, drag, isActive }: RenderItem<Item>) => (
|
||||
<ManageWalletsListItem
|
||||
item={item}
|
||||
isDraggingDisabled={state.searchQuery.length > 0 || state.isSearchFocused}
|
||||
state={state}
|
||||
navigateToWallet={navigateToWallet}
|
||||
renderHighlightedText={renderHighlightedText}
|
||||
isPlaceHolder
|
||||
handleDeleteWallet={handleDeleteWallet}
|
||||
handleToggleHideBalance={handleToggleHideBalance}
|
||||
/>
|
||||
),
|
||||
[handleDeleteWallet, handleToggleHideBalance, navigateToWallet, renderHighlightedText, state],
|
||||
);
|
||||
|
||||
const onChangeOrder = useCallback(() => {
|
||||
@ -288,16 +468,20 @@ const ManageWallets: React.FC = () => {
|
||||
const onRelease = useCallback(() => {
|
||||
triggerHapticFeedback(HapticFeedbackTypes.ImpactLight);
|
||||
}, []);
|
||||
const onDragEnd = useCallback(
|
||||
({ data }: { data: Item[] }) => {
|
||||
const updatedWallets = data.filter((item): item is WalletItem => item.type === ItemType.WalletSection).map(item => item.data);
|
||||
|
||||
const onDragEnd = useCallback(({ data }: any) => {
|
||||
dispatch({ type: SET_ORDER, payload: data });
|
||||
}, []);
|
||||
dispatch({ type: SET_INITIAL_ORDER, payload: { wallets: updatedWallets, txMetadata: state.txMetadata } });
|
||||
},
|
||||
[state.txMetadata],
|
||||
);
|
||||
|
||||
const _keyExtractor = useCallback((_item: any, index: number) => index.toString(), []);
|
||||
const keyExtractor = useCallback((item: Item, index: number) => index.toString(), []);
|
||||
|
||||
const renderHeader = useMemo(() => {
|
||||
if (!state.searchQuery) return null;
|
||||
const hasWallets = state.walletData.length > 0;
|
||||
const hasWallets = state.wallets.length > 0;
|
||||
const filteredTxMetadata = Object.entries(state.txMetadata).filter(([_, tx]) =>
|
||||
tx.memo?.toLowerCase().includes(state.searchQuery.toLowerCase()),
|
||||
);
|
||||
@ -307,24 +491,43 @@ const ManageWallets: React.FC = () => {
|
||||
!hasWallets &&
|
||||
!hasTransactions && <Text style={[styles.noResultsText, stylesHook.noResultsText]}>{loc.wallets.no_results_found}</Text>
|
||||
);
|
||||
}, [state.searchQuery, state.walletData.length, state.txMetadata, stylesHook.noResultsText]);
|
||||
}, [state.searchQuery, state.wallets.length, state.txMetadata, stylesHook.noResultsText]);
|
||||
|
||||
return (
|
||||
<GestureHandlerRootView style={[styles.root, stylesHook.root]}>
|
||||
<DraggableFlatList
|
||||
ref={sortableList}
|
||||
contentInsetAdjustmentBehavior="automatic"
|
||||
automaticallyAdjustContentInsets
|
||||
data={state.order}
|
||||
keyExtractor={_keyExtractor}
|
||||
renderItem={renderItem}
|
||||
onChangeOrder={onChangeOrder}
|
||||
onDragBegin={onDragBegin}
|
||||
onRelease={onRelease}
|
||||
onDragEnd={onDragEnd}
|
||||
containerStyle={styles.root}
|
||||
ListHeaderComponent={renderHeader}
|
||||
/>
|
||||
<GestureHandlerRootView style={[{ backgroundColor: colors.background }, styles.root]}>
|
||||
<NestableScrollContainer contentInsetAdjustmentBehavior="automatic" automaticallyAdjustContentInsets>
|
||||
{renderHeader}
|
||||
<NestableDraggableFlatList
|
||||
data={state.tempOrder.filter((item): item is WalletItem => item.type === ItemType.WalletSection)}
|
||||
extraData={state.tempOrder}
|
||||
keyExtractor={keyExtractor}
|
||||
renderItem={renderWalletItem}
|
||||
onChangeOrder={onChangeOrder}
|
||||
onDragBegin={onDragBegin}
|
||||
onPlaceholderIndexChange={onChangeOrder}
|
||||
onRelease={onRelease}
|
||||
delayLongPress={150}
|
||||
useNativeDriver={true}
|
||||
dragItemOverflow
|
||||
autoscrollThreshold={1}
|
||||
renderPlaceholder={renderPlaceholder}
|
||||
autoscrollSpeed={0.5}
|
||||
contentInsetAdjustmentBehavior="automatic"
|
||||
automaticallyAdjustContentInsets
|
||||
onDragEnd={onDragEnd}
|
||||
containerStyle={styles.root}
|
||||
/>
|
||||
<NestableDraggableFlatList
|
||||
data={state.tempOrder.filter((item): item is TransactionItem => item.type === ItemType.TransactionSection)}
|
||||
keyExtractor={keyExtractor}
|
||||
renderItem={renderWalletItem}
|
||||
dragItemOverflow
|
||||
containerStyle={styles.root}
|
||||
contentInsetAdjustmentBehavior="automatic"
|
||||
automaticallyAdjustContentInsets
|
||||
useNativeDriver={true}
|
||||
/>
|
||||
</NestableScrollContainer>
|
||||
</GestureHandlerRootView>
|
||||
);
|
||||
};
|
||||
@ -335,9 +538,6 @@ const styles = StyleSheet.create({
|
||||
root: {
|
||||
flex: 1,
|
||||
},
|
||||
padding16: {
|
||||
padding: 16,
|
||||
},
|
||||
button: {
|
||||
padding: 16,
|
||||
},
|
||||
@ -349,9 +549,6 @@ const styles = StyleSheet.create({
|
||||
justifyContent: 'center',
|
||||
marginTop: 34,
|
||||
},
|
||||
});
|
||||
|
||||
const iStyles = StyleSheet.create({
|
||||
highlightedContainer: {
|
||||
backgroundColor: 'white',
|
||||
borderColor: 'black',
|
||||
|
@ -241,12 +241,8 @@ const WalletsList: React.FC = () => {
|
||||
}, [stylesHook.listHeaderBack, stylesHook.listHeaderText]);
|
||||
|
||||
const handleLongPress = useCallback(() => {
|
||||
if (wallets.length > 1) {
|
||||
navigate('ManageWallets');
|
||||
} else {
|
||||
triggerHapticFeedback(HapticFeedbackTypes.NotificationError);
|
||||
}
|
||||
}, [navigate, wallets.length]);
|
||||
navigate('ManageWallets');
|
||||
}, [navigate]);
|
||||
|
||||
const renderTransactionListsRow = useCallback(
|
||||
(item: ExtendedTransaction) => (
|
||||
@ -296,14 +292,18 @@ const WalletsList: React.FC = () => {
|
||||
case WalletsListSections.TRANSACTIONS:
|
||||
return renderListHeaderComponent();
|
||||
case WalletsListSections.CAROUSEL: {
|
||||
return !isLargeScreen && isTotalBalanceEnabled ? <TotalWalletsBalance /> : null;
|
||||
return !isLargeScreen && isTotalBalanceEnabled ? (
|
||||
<View style={stylesHook.walletsListWrapper}>
|
||||
<TotalWalletsBalance />
|
||||
</View>
|
||||
) : null;
|
||||
}
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
},
|
||||
[isLargeScreen, isTotalBalanceEnabled, renderListHeaderComponent],
|
||||
[isLargeScreen, isTotalBalanceEnabled, renderListHeaderComponent, stylesHook.walletsListWrapper],
|
||||
);
|
||||
|
||||
const renderSectionFooter = useCallback(
|
||||
|
@ -9,3 +9,38 @@
|
||||
if (zoomMode == "off") return true
|
||||
val cameraControl = camera?.cameraControl ?: return true
|
||||
val zoom = camera?.cameraInfo?.zoomState?.value?.zoomRatio ?: return true
|
||||
|
||||
--- ../node_modules/react-native-camera-kit/dist/CameraScreen.js 2024-09-01 13:00:57
|
||||
+++ ../node_modules/react-native-camera-kit/dist/CameraScreen.js 2024-09-01 13:00:46
|
||||
@@ -61,14 +61,14 @@
|
||||
</TouchableOpacity>));
|
||||
}
|
||||
renderTorchButton() {
|
||||
- return (!this.isCaptureRetakeMode() && (<TouchableOpacity style={{ paddingHorizontal: 15 }} onPress={() => this.onSetTorch()}>
|
||||
- <Image style={[{ flex: 1, justifyContent: 'center' }, this.props.torchImageStyle]} source={this.state.torchMode ? this.props.torchOnImage : this.props.torchOffImage} resizeMode="contain"/>
|
||||
+ return (!this.isCaptureRetakeMode() && (<TouchableOpacity style={{ backgroundColor: '#FFFFFF', borderRadius: 20 }} onPress={() => this.onSetTorch()}>
|
||||
+ <Image style={[{ width: 40, height: 40, justifyContent: 'center' }, this.props.torchImageStyle]} source={this.state.torchMode ? this.props.torchOnImage : this.props.torchOffImage} resizeMode="contain"/>
|
||||
</TouchableOpacity>));
|
||||
}
|
||||
renderSwitchCameraButton() {
|
||||
return (this.props.cameraFlipImage &&
|
||||
- !this.isCaptureRetakeMode() && (<TouchableOpacity style={{ paddingHorizontal: 15 }} onPress={() => this.onSwitchCameraPressed()}>
|
||||
- <Image style={{ flex: 1, justifyContent: 'center' }} source={this.props.cameraFlipImage} resizeMode="contain"/>
|
||||
+ !this.isCaptureRetakeMode() && (<TouchableOpacity style={{ }} onPress={() => this.onSwitchCameraPressed()}>
|
||||
+ <Image style={{ width: 40, height: 40, justifyContent: 'center' }} source={this.props.cameraFlipImage} resizeMode="contain"/>
|
||||
</TouchableOpacity>));
|
||||
}
|
||||
renderTopButtons() {
|
||||
\ No newline at end of file
|
||||
@@ -228,8 +228,8 @@
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
- paddingTop: 8,
|
||||
- paddingBottom: 0,
|
||||
+ paddingTop:44,
|
||||
+ paddingHorizontal: 16,
|
||||
},
|
||||
cameraContainer: Object.assign({}, Platform.select({
|
||||
android: {
|
||||
\ No newline at end of file
|
||||
|
Loading…
Reference in New Issue
Block a user