Merge branch 'master' into drawertoggle

This commit is contained in:
Marcos Rodriguez Velez 2024-09-15 12:55:42 -04:00
commit 6cfe57d161
99 changed files with 12555 additions and 3806 deletions

View File

@ -19,6 +19,7 @@
"react/display-name": "off",
"react-native/no-inline-styles": "error",
"react-native/no-unused-styles": "error",
"react/no-is-mounted": "off",
"react-native/no-single-element-style-arrays": "error",
"prettier/prettier": [
"warn",

View File

@ -48,13 +48,13 @@ jobs:
bundle install --jobs 4 --retry 3 --quiet
- name: Install node_modules
run: npm install --production
run: npm install --omit=dev --yes
- name: Install CocoaPods Dependencies
run: |
bundle exec fastlane ios install_pods
- name: Cache CocoaPods Pods
uses: actions/cache@v2
uses: actions/cache@v4
with:
path: ios/Pods
key: ${{ runner.os }}-pods-${{ hashFiles('**/Podfile.lock') }}
@ -88,7 +88,7 @@ jobs:
bundle exec fastlane ios setup_provisioning_profiles
- name: Cache Provisioning Profiles
id: cache_provisioning_profiles
uses: actions/cache@v2
uses: actions/cache@v4
with:
path: ~/Library/MobileDevice/Provisioning Profiles
key: ${{ runner.os }}-provisioning-profiles-${{ github.sha }}
@ -131,14 +131,14 @@ jobs:
- name: Build App
run: bundle exec fastlane ios build_app_lane
- name: Upload IPA as Artifact
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v4
with:
name: BlueWallet.${{env.PROJECT_VERSION}}(${{env.NEW_BUILD_NUMBER}}).ipa
path: ./ios/build/BlueWallet.${{env.PROJECT_VERSION}}(${{env.NEW_BUILD_NUMBER}}).ipa
path: ./build/BlueWallet.${{env.PROJECT_VERSION}}(${{env.NEW_BUILD_NUMBER}}).ipa
testflight-upload:
needs: build
runs-on: macos-14
runs-on: macos-latest
if: github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'testflight')
env:
APPLE_ID: ${{ secrets.APPLE_ID }}
@ -154,7 +154,7 @@ jobs:
ruby-version: 3.1.6
bundler-cache: true
- name: Cache Ruby Gems
uses: actions/cache@v2
uses: actions/cache@v4
with:
path: vendor/bundle
key: ${{ runner.os }}-gems-${{ hashFiles('**/Gemfile.lock') }}
@ -165,15 +165,15 @@ jobs:
bundle config path vendor/bundle
bundle install --jobs 4 --retry 3 --quiet
- name: Download IPA from Artifact
uses: actions/download-artifact@v2
uses: actions/download-artifact@v4
with:
name: BlueWallet.${{ needs.build.outputs.project_version }}(${{ needs.build.outputs.new_build_number }}).ipa
path: ./ios/build
path: ./
- name: Create App Store Connect API Key JSON
run: echo '${{ secrets.APP_STORE_CONNECT_API_KEY_CONTENT }}' > ./ios/appstore_api_key.json
run: echo '${{ secrets.APP_STORE_CONNECT_API_KEY_CONTENT }}' > ./appstore_api_key.json
- name: Upload to TestFlight
env:
APP_STORE_CONNECT_API_KEY_PATH: $(pwd)/ios/appstore_api_key.p8
APP_STORE_CONNECT_API_KEY_PATH: $(pwd)/appstore_api_key.p8
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
GIT_ACCESS_TOKEN: ${{ secrets.GIT_ACCESS_TOKEN }}
GIT_URL: ${{ secrets.GIT_URL }}

View File

@ -25,7 +25,7 @@ jobs:
node-version: 20
- name: Use npm caches
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}
@ -40,7 +40,7 @@ jobs:
cache: 'gradle'
- name: Install node_modules
run: npm install --production
run: npm install --omit=dev --yes
- name: Set up Ruby
uses: ruby/setup-ruby@v1
@ -49,7 +49,7 @@ jobs:
bundler-cache: true
- name: Cache Ruby Gems
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: vendor/bundle
key: ${{ runner.os }}-gems-${{ hashFiles('**/Gemfile.lock') }}
@ -79,18 +79,21 @@ jobs:
id: determine_apk_path
run: |
VERSION_NAME=$(grep versionName android/app/build.gradle | awk '{print $2}' | tr -d '"')
BRANCH_NAME=$(echo ${{ github.head_ref || github.ref_name }} | sed 's/[^a-zA-Z0-9_-]/-/g')
if [ "$BRANCH_NAME" != "master" ]; then
BRANCH_NAME=${GITHUB_HEAD_REF:-${GITHUB_REF_NAME}}
BRANCH_NAME=$(echo "$BRANCH_NAME" | sed 's/[^a-zA-Z0-9_-]/-/g')
if [ -n "$BRANCH_NAME" ] && [ "$BRANCH_NAME" != "master" ]; then
EXPECTED_FILENAME="BlueWallet-${VERSION_NAME}-${NEW_BUILD_NUMBER}-${BRANCH_NAME}.apk"
else
EXPECTED_FILENAME="BlueWallet-${VERSION_NAME}-${NEW_BUILD_NUMBER}.apk"
fi
APK_PATH="android/app/build/outputs/apk/release/${EXPECTED_FILENAME}"
echo "EXPECTED_FILENAME=${EXPECTED_FILENAME}" >> $GITHUB_ENV
echo "APK_PATH=${APK_PATH}" >> $GITHUB_ENV
- name: Upload APK as artifact
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: signed-apk
path: ${{ env.APK_PATH }}
@ -114,7 +117,7 @@ jobs:
run: bundle install --jobs 4 --retry 3
- name: Download APK artifact
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
with:
name: signed-apk

View File

@ -30,16 +30,9 @@ jobs:
restore-keys: |
${{ runner.os }}-npm-
- name: Use node_modules caches
id: cache-nm
uses: actions/cache@v4
with:
path: node_modules
key: ${{ runner.os }}-nm-${{ hashFiles('package-lock.json') }}
- name: Install node_modules
if: steps.cache-nm.outputs.cache-hit != 'true'
run: npm install
run: npm ci
- name: Run tests
run: npm test || npm test || npm test || npm test
@ -55,6 +48,9 @@ jobs:
MNEMONICS_COLDCARD: ${{ secrets.MNEMONICS_COLDCARD }}
RETRY: 1
- name: Prune devDependencies
run: npm prune --omit=dev
e2e:
runs-on: ubuntu-latest
steps:

97
.github/workflows/lockfiles_update.yml vendored Normal file
View File

@ -0,0 +1,97 @@
name: Lock Files Update
on:
workflow_dispatch:
push:
branches:
- master
jobs:
pod-update:
runs-on: macos-latest
permissions:
contents: write
steps:
- name: Checkout master branch
uses: actions/checkout@v4
with:
ref: master # Ensures we're checking out the master branch
fetch-depth: 0 # Ensures full history to enable branch deletion and recreation
- name: Delete existing branch
run: |
git push origin --delete pod-update-branch || echo "Branch does not exist, continuing..."
git branch -D pod-update-branch || echo "Local branch does not exist, continuing..."
- name: Create new branch from master
run: git checkout -b pod-update-branch # Create a new branch from the master branch
- name: Specify node version
uses: actions/setup-node@v4
with:
node-version: 20
- name: Install node modules
run: npm install
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: 3.1.6
bundler-cache: true
- name: Install and update Ruby Gems
run: |
bundle install
- name: Install CocoaPods Dependencies
run: |
cd ios
pod install
pod update
- name: Check for changes
id: check-changes
run: |
git diff --quiet package-lock.json ios/Podfile.lock || echo "Changes detected"
continue-on-error: true
- name: Stop job if no changes
if: steps.check-changes.outcome == 'success'
run: |
echo "No changes detected in package-lock.json or Podfile.lock. Stopping the job."
exit 0
- name: Commit changes
if: steps.check-changes.outcome != 'success'
run: |
git add package-lock.json ios/Podfile.lock
git commit -m "Update lock files"
# Step 10: Get the list of changed files for PR description
- name: Get changed files for PR description
id: get-changes
if: steps.check-changes.outcome != 'success'
run: |
git diff --name-only HEAD^ HEAD > changed_files.txt
echo "CHANGES=$(cat changed_files.txt)" >> $GITHUB_ENV
# Step 11: Push the changes and create the PR using the LockFiles PAT
- name: Push and create PR
if: steps.check-changes.outcome != 'success'
run: |
git push origin pod-update-branch
gh pr create --title "Lock Files Updates" --body "The following lock files were updated:\n\n${{ env.CHANGES }}" --base master
env:
GITHUB_TOKEN: ${{ secrets.LOCKFILES_WORKFLOW }} # Use the LockFiles PAT for PR creation
cleanup:
runs-on: macos-latest
if: github.event.pull_request.merged == true || github.event.pull_request.state == 'closed'
needs: pod-update
steps:
- name: Delete branch after PR merge/close
run: |
git push origin --delete pod-update-branch

View File

@ -1,22 +1,8 @@
/* eslint react/prop-types: "off", react-native/no-inline-styles: "off" */
import Clipboard from '@react-native-clipboard/clipboard';
import React, { forwardRef } from 'react';
import {
ActivityIndicator,
Dimensions,
I18nManager,
InputAccessoryView,
Keyboard,
Platform,
StyleSheet,
TextInput,
TouchableOpacity,
View,
} from 'react-native';
import { ActivityIndicator, Dimensions, I18nManager, Platform, StyleSheet, TextInput, TouchableOpacity, View } from 'react-native';
import { Icon, Text } from '@rneui/themed';
import { useTheme } from './components/themes';
import loc from './loc';
const { height, width } = Dimensions.get('window');
const aspectRatio = height / width;
@ -38,8 +24,8 @@ export const BlueButtonLink = forwardRef((props, ref) => {
<TouchableOpacity
accessibilityRole="button"
style={{
minHeight: 60,
minWidth: 100,
minHeight: 36,
justifyContent: 'center',
}}
{...props}
@ -137,60 +123,6 @@ export const BlueSpacing10 = props => {
return <View {...props} style={{ height: 10, opacity: 0 }} />;
};
export const BlueDismissKeyboardInputAccessory = () => {
const { colors } = useTheme();
BlueDismissKeyboardInputAccessory.InputAccessoryViewID = 'BlueDismissKeyboardInputAccessory';
return Platform.OS !== 'ios' ? null : (
<InputAccessoryView nativeID={BlueDismissKeyboardInputAccessory.InputAccessoryViewID}>
<View
style={{
backgroundColor: colors.inputBackgroundColor,
height: 44,
flex: 1,
flexDirection: 'row',
justifyContent: 'flex-end',
alignItems: 'center',
}}
>
<BlueButtonLink title={loc.send.input_done} onPress={Keyboard.dismiss} />
</View>
</InputAccessoryView>
);
};
export const BlueDoneAndDismissKeyboardInputAccessory = props => {
const { colors } = useTheme();
BlueDoneAndDismissKeyboardInputAccessory.InputAccessoryViewID = 'BlueDoneAndDismissKeyboardInputAccessory';
const onPasteTapped = async () => {
const clipboard = await Clipboard.getString();
props.onPasteTapped(clipboard);
};
const inputView = (
<View
style={{
backgroundColor: colors.inputBackgroundColor,
flexDirection: 'row',
justifyContent: 'flex-end',
alignItems: 'center',
maxHeight: 44,
}}
>
<BlueButtonLink title={loc.send.input_clear} onPress={props.onClearTapped} />
<BlueButtonLink title={loc.send.input_paste} onPress={onPasteTapped} />
<BlueButtonLink title={loc.send.input_done} onPress={Keyboard.dismiss} />
</View>
);
if (Platform.OS === 'ios') {
return <InputAccessoryView nativeID={BlueDoneAndDismissKeyboardInputAccessory.InputAccessoryViewID}>{inputView}</InputAccessoryView>;
} else {
return inputView;
}
};
export const BlueLoading = props => {
return (
<View style={{ flex: 1, justifyContent: 'center' }} {...props}>

View File

@ -24,17 +24,17 @@ GEM
artifactory (3.0.17)
atomos (0.1.3)
aws-eventstream (1.3.0)
aws-partitions (1.970.0)
aws-sdk-core (3.202.2)
aws-partitions (1.973.0)
aws-sdk-core (3.204.0)
aws-eventstream (~> 1, >= 1.3.0)
aws-partitions (~> 1, >= 1.651.0)
aws-sigv4 (~> 1.9)
jmespath (~> 1, >= 1.6.1)
aws-sdk-kms (1.88.0)
aws-sdk-core (~> 3, >= 3.201.0)
aws-sdk-kms (1.90.0)
aws-sdk-core (~> 3, >= 3.203.0)
aws-sigv4 (~> 1.5)
aws-sdk-s3 (1.159.0)
aws-sdk-core (~> 3, >= 3.201.0)
aws-sdk-s3 (1.161.0)
aws-sdk-core (~> 3, >= 3.203.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.5)
aws-sigv4 (1.9.1)
@ -223,7 +223,7 @@ GEM
logger (1.6.1)
mime-types (3.5.2)
mime-types-data (~> 3.2015)
mime-types-data (3.2024.0820)
mime-types-data (3.2024.0903)
mini_magick (4.13.2)
mini_mime (1.1.5)
minitest (5.25.1)
@ -250,8 +250,7 @@ GEM
mime-types (>= 1.16, < 4.0)
netrc (~> 0.8)
retriable (3.1.2)
rexml (3.3.6)
strscan
rexml (3.3.7)
rouge (2.0.7)
ruby-macho (2.5.1)
ruby2_keywords (0.0.5)
@ -266,7 +265,6 @@ GEM
simctl (1.6.10)
CFPropertyList
naturally
strscan (3.1.0)
terminal-notifier (2.0.0)
terminal-table (3.0.2)
unicode-display_width (>= 1.1.1, < 3)

View File

@ -83,7 +83,7 @@ android {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 1
versionName "7.0.4"
versionName "7.0.5"
testBuildType System.getProperty('testBuildType', 'debug')
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
}

View File

@ -28,8 +28,8 @@ class BitcoinPriceWidget : AppWidgetProvider() {
}
private fun clearCache(context: Context) {
val sharedPref = context.getSharedPreferences("widget_prefs", Context.MODE_PRIVATE)
sharedPref.edit().clear().apply()
Log.d("BitcoinPriceWidget", "Cache cleared")
val sharedPref = context.getSharedPreferences("group.io.bluewallet.bluewallet", Context.MODE_PRIVATE)
sharedPref.edit().clear().apply() // Clear all preferences in the group
Log.d("BitcoinPriceWidget", "Cache cleared from group.io.bluewallet.bluewallet")
}
}

View File

@ -8,6 +8,7 @@ import android.util.Log
import android.view.View
import android.widget.RemoteViews
import androidx.work.*
import java.text.DecimalFormatSymbols
import java.text.NumberFormat
import java.text.SimpleDateFormat
import java.util.*
@ -33,17 +34,22 @@ class WidgetUpdateWorker(context: Context, workerParams: WorkerParameters) : Wor
}
}
private lateinit var sharedPref: SharedPreferences
private lateinit var preferenceChangeListener: SharedPreferences.OnSharedPreferenceChangeListener
override fun doWork(): Result {
Log.d(TAG, "Widget update worker running")
sharedPref = applicationContext.getSharedPreferences("group.io.bluewallet.bluewallet", Context.MODE_PRIVATE)
registerPreferenceChangeListener()
val appWidgetManager = AppWidgetManager.getInstance(applicationContext)
val thisWidget = ComponentName(applicationContext, BitcoinPriceWidget::class.java)
val appWidgetIds = appWidgetManager.getAppWidgetIds(thisWidget)
val views = RemoteViews(applicationContext.packageName, R.layout.widget_layout)
val sharedPref = applicationContext.getSharedPreferences("widget_prefs", Context.MODE_PRIVATE)
val preferredCurrency = sharedPref.getString("preferredCurrency", "USD")
val preferredCurrencyLocale = sharedPref.getString("preferredCurrencyLocale", "en-US")
val preferredCurrency = sharedPref.getString("preferredCurrency", null) ?: "USD"
val preferredCurrencyLocale = sharedPref.getString("preferredCurrencyLocale", null) ?: "en-US"
val previousPrice = sharedPref.getString("previous_price", null)
val currentTime = SimpleDateFormat("hh:mm a", Locale.getDefault()).format(Date())
@ -51,13 +57,47 @@ class WidgetUpdateWorker(context: Context, workerParams: WorkerParameters) : Wor
fetchPrice(preferredCurrency) { fetchedPrice, error ->
handlePriceResult(
appWidgetManager, appWidgetIds, views, sharedPref,
fetchedPrice, previousPrice, currentTime, preferredCurrencyLocale, error
fetchedPrice, previousPrice, currentTime, preferredCurrency, preferredCurrencyLocale, error
)
}
return Result.success()
}
private fun registerPreferenceChangeListener() {
preferenceChangeListener = SharedPreferences.OnSharedPreferenceChangeListener { sharedPreferences, key ->
if (key == "preferredCurrency" || key == "preferredCurrencyLocale" || key == "previous_price") {
Log.d(TAG, "Preference changed: $key")
updateWidgetOnPreferenceChange()
}
}
sharedPref.registerOnSharedPreferenceChangeListener(preferenceChangeListener)
}
override fun onStopped() {
super.onStopped()
sharedPref.unregisterOnSharedPreferenceChangeListener(preferenceChangeListener)
}
private fun updateWidgetOnPreferenceChange() {
val appWidgetManager = AppWidgetManager.getInstance(applicationContext)
val thisWidget = ComponentName(applicationContext, BitcoinPriceWidget::class.java)
val appWidgetIds = appWidgetManager.getAppWidgetIds(thisWidget)
val views = RemoteViews(applicationContext.packageName, R.layout.widget_layout)
val preferredCurrency = sharedPref.getString("preferredCurrency", null) ?: "USD"
val preferredCurrencyLocale = sharedPref.getString("preferredCurrencyLocale", null) ?: "en-US"
val previousPrice = sharedPref.getString("previous_price", null)
val currentTime = SimpleDateFormat("hh:mm a", Locale.getDefault()).format(Date())
fetchPrice(preferredCurrency) { fetchedPrice, error ->
handlePriceResult(
appWidgetManager, appWidgetIds, views, sharedPref,
fetchedPrice, previousPrice, currentTime, preferredCurrency, preferredCurrencyLocale, error
)
}
}
private fun handlePriceResult(
appWidgetManager: AppWidgetManager,
appWidgetIds: IntArray,
@ -66,6 +106,7 @@ class WidgetUpdateWorker(context: Context, workerParams: WorkerParameters) : Wor
fetchedPrice: String?,
previousPrice: String?,
currentTime: String,
preferredCurrency: String?,
preferredCurrencyLocale: String?,
error: String?
) {
@ -77,11 +118,11 @@ class WidgetUpdateWorker(context: Context, workerParams: WorkerParameters) : Wor
if (!isPriceCached) {
showLoadingError(views)
} else {
displayCachedPrice(views, previousPrice, currentTime, preferredCurrencyLocale)
displayCachedPrice(views, previousPrice, currentTime, preferredCurrency, preferredCurrencyLocale)
}
} else {
displayFetchedPrice(
views, fetchedPrice!!, previousPrice, currentTime, preferredCurrencyLocale
views, fetchedPrice!!, previousPrice, currentTime, preferredCurrency, preferredCurrencyLocale
)
savePrice(sharedPref, fetchedPrice)
}
@ -103,11 +144,10 @@ class WidgetUpdateWorker(context: Context, workerParams: WorkerParameters) : Wor
views: RemoteViews,
previousPrice: String?,
currentTime: String,
preferredCurrency: String?,
preferredCurrencyLocale: String?
) {
val currencyFormat = NumberFormat.getCurrencyInstance(Locale.forLanguageTag(preferredCurrencyLocale!!)).apply {
maximumFractionDigits = 0
}
val currencyFormat = getCurrencyFormat(preferredCurrency, preferredCurrencyLocale)
views.apply {
setViewVisibility(R.id.loading_indicator, View.GONE)
@ -125,12 +165,11 @@ class WidgetUpdateWorker(context: Context, workerParams: WorkerParameters) : Wor
fetchedPrice: String,
previousPrice: String?,
currentTime: String,
preferredCurrency: String?,
preferredCurrencyLocale: String?
) {
val currentPrice = fetchedPrice.toDouble().let { it.toInt() } // Remove cents
val currencyFormat = NumberFormat.getCurrencyInstance(Locale.forLanguageTag(preferredCurrencyLocale!!)).apply {
maximumFractionDigits = 0
}
val currentPrice = fetchedPrice.toDouble().toInt() // Remove cents
val currencyFormat = getCurrencyFormat(preferredCurrency, preferredCurrencyLocale)
views.apply {
setViewVisibility(R.id.loading_indicator, View.GONE)
@ -153,6 +192,30 @@ class WidgetUpdateWorker(context: Context, workerParams: WorkerParameters) : Wor
}
}
private fun getCurrencyFormat(currencyCode: String?, localeString: String?): NumberFormat {
val localeParts = localeString?.split("-") ?: listOf("en", "US")
val locale = if (localeParts.size == 2) {
Locale(localeParts[0], localeParts[1])
} else {
Locale.getDefault()
}
val currencyFormat = NumberFormat.getCurrencyInstance(locale)
val currency = try {
Currency.getInstance(currencyCode ?: "USD")
} catch (e: IllegalArgumentException) {
Currency.getInstance("USD") // Default to USD if an invalid code is provided
}
currencyFormat.currency = currency
currencyFormat.maximumFractionDigits = 0 // No cents
// Remove the ISO country code and keep only the symbol
val decimalFormatSymbols = (currencyFormat as java.text.DecimalFormat).decimalFormatSymbols
decimalFormatSymbols.currencySymbol = currency.symbol
currencyFormat.decimalFormatSymbols = decimalFormatSymbols
return currencyFormat
}
private fun fetchPrice(currency: String?, callback: (String?, String?) -> Unit) {
val price = MarketAPI.fetchPrice(applicationContext, currency ?: "USD")
if (price == null) {

View File

@ -2,7 +2,7 @@
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:initialLayout="@layout/widget_layout"
android:minWidth="160dp"
android:minHeight="80dp"
android:minHeight="100dp"
android:updatePeriodMillis="0"
android:widgetCategory="home_screen"
android:previewImage="@drawable/widget_preview"

View File

@ -93,7 +93,10 @@ export const writeFileAndExport = async function (fileName: string, contents: st
export const openSignedTransaction = async function (): Promise<string | false> {
try {
const res = await DocumentPicker.pickSingle({
type: Platform.OS === 'ios' ? ['io.bluewallet.psbt', 'io.bluewallet.psbt.txn'] : [DocumentPicker.types.allFiles],
type:
Platform.OS === 'ios'
? ['io.bluewallet.psbt', 'io.bluewallet.psbt.txn', DocumentPicker.types.json]
: [DocumentPicker.types.allFiles],
});
return await _readPsbtFileIntoBase64(res.uri);
@ -160,7 +163,7 @@ export const showFilePickerAndReadFile = async function (): Promise<{ data: stri
'io.bluewallet.psbt.txn',
'io.bluewallet.backup',
DocumentPicker.types.plainText,
'public.json',
DocumentPicker.types.json,
DocumentPicker.types.images,
]
: [DocumentPicker.types.allFiles],

View File

@ -67,13 +67,12 @@ const isReactNative = typeof navigator !== 'undefined' && navigator?.product ===
export class BlueApp {
static FLAG_ENCRYPTED = 'data_encrypted';
static LNDHUB = 'lndhub';
static ADVANCED_MODE_ENABLED = 'advancedmodeenabled';
static DO_NOT_TRACK = 'donottrack';
static HANDOFF_STORAGE_KEY = 'HandOff';
private static _instance: BlueApp | null = null;
static keys2migrate = [BlueApp.HANDOFF_STORAGE_KEY, BlueApp.DO_NOT_TRACK, BlueApp.ADVANCED_MODE_ENABLED];
static keys2migrate = [BlueApp.HANDOFF_STORAGE_KEY, BlueApp.DO_NOT_TRACK];
public cachedPassword?: false | string;
public tx_metadata: TTXMetadata;
@ -882,17 +881,6 @@ export class BlueApp {
return finalBalance;
};
isAdvancedModeEnabled = async (): Promise<boolean> => {
try {
return !!(await AsyncStorage.getItem(BlueApp.ADVANCED_MODE_ENABLED));
} catch (_) {}
return false;
};
setIsAdvancedModeEnabled = async (value: boolean) => {
await AsyncStorage.setItem(BlueApp.ADVANCED_MODE_ENABLED, value ? '1' : '');
};
isHandoffEnabled = async (): Promise<boolean> => {
try {
return !!(await AsyncStorage.getItem(BlueApp.HANDOFF_STORAGE_KEY));

View File

@ -5,6 +5,7 @@ import { LegacyWallet } from './legacy-wallet';
export class LightningCustodianWallet extends LegacyWallet {
static readonly type = 'lightningCustodianWallet';
static readonly typeReadable = 'Lightning';
static readonly subtitleReadable = 'LNDhub';
// @ts-ignore: override
public readonly type = LightningCustodianWallet.type;
// @ts-ignore: override

View File

@ -0,0 +1,53 @@
import React, { useCallback, useMemo } from 'react';
import { StyleSheet, TouchableOpacity, GestureResponderEvent } from 'react-native';
import { Icon } from '@rneui/themed';
import { useTheme } from './themes';
import ToolTipMenu from './TooltipMenu';
import { CommonToolTipActions } from '../typings/CommonToolTipActions';
import loc from '../loc';
import { navigationRef } from '../NavigationService';
type AddWalletButtonProps = {
onPress?: (event: GestureResponderEvent) => void;
};
const styles = StyleSheet.create({
ball: {
width: 30,
height: 30,
borderRadius: 15,
justifyContent: 'center',
alignContent: 'center',
},
});
const AddWalletButton: React.FC<AddWalletButtonProps> = ({ onPress }) => {
const { colors } = useTheme();
const stylesHook = StyleSheet.create({
ball: {
backgroundColor: colors.buttonBackgroundColor,
},
});
const onPressMenuItem = useCallback((action: string) => {
switch (action) {
case CommonToolTipActions.ImportWallet.id:
navigationRef.current?.navigate('AddWalletRoot', { screen: 'ImportWallet' });
break;
default:
break;
}
}, []);
const actions = useMemo(() => [CommonToolTipActions.ImportWallet], []);
return (
<ToolTipMenu accessibilityRole="button" accessibilityLabel={loc.wallets.add_title} onPressMenuItem={onPressMenuItem} actions={actions}>
<TouchableOpacity style={[styles.ball, stylesHook.ball]} onPress={onPress}>
<Icon name="add" size={22} type="ionicons" color={colors.foregroundColor} />
</TouchableOpacity>
</ToolTipMenu>
);
};
export default AddWalletButton;

View File

@ -69,8 +69,6 @@ interface SettingsContextType {
setIsHandOffUseEnabledAsyncStorage: (value: boolean) => Promise<void>;
isPrivacyBlurEnabled: boolean;
setIsPrivacyBlurEnabledState: (value: boolean) => void;
isAdvancedModeEnabled: boolean;
setIsAdvancedModeEnabledStorage: (value: boolean) => Promise<void>;
isDoNotTrackEnabled: boolean;
setDoNotTrackStorage: (value: boolean) => Promise<void>;
isWidgetBalanceDisplayAllowed: boolean;
@ -98,8 +96,6 @@ const defaultSettingsContext: SettingsContextType = {
setIsHandOffUseEnabledAsyncStorage: async () => {},
isPrivacyBlurEnabled: true,
setIsPrivacyBlurEnabledState: () => {},
isAdvancedModeEnabled: false,
setIsAdvancedModeEnabledStorage: async () => {},
isDoNotTrackEnabled: false,
setDoNotTrackStorage: async () => {},
isWidgetBalanceDisplayAllowed: true,
@ -129,8 +125,6 @@ export const SettingsProvider: React.FC<{ children: React.ReactNode }> = ({ chil
const [isHandOffUseEnabled, setHandOffUseEnabled] = useState<boolean>(false);
// PrivacyBlur
const [isPrivacyBlurEnabled, setIsPrivacyBlurEnabled] = useState<boolean>(true);
// AdvancedMode
const [isAdvancedModeEnabled, setIsAdvancedModeEnabled] = useState<boolean>(false);
// DoNotTrack
const [isDoNotTrackEnabled, setIsDoNotTrackEnabled] = useState<boolean>(false);
// WidgetCommunication
@ -148,19 +142,10 @@ export const SettingsProvider: React.FC<{ children: React.ReactNode }> = ({ chil
// Toggle Drawer (for screens like Manage Wallets or ScanQRCode)
const [isDrawerShouldHide, setIsDrawerShouldHide] = useState<boolean>(false);
const advancedModeStorage = useAsyncStorage(BlueApp.ADVANCED_MODE_ENABLED);
const languageStorage = useAsyncStorage(STORAGE_KEY);
const { walletsInitialized } = useStorage();
useEffect(() => {
advancedModeStorage
.getItem()
.then(advMode => {
console.debug('SettingsContext advMode:', advMode);
setIsAdvancedModeEnabled(advMode ? JSON.parse(advMode) : false);
})
.catch(error => console.error('Error fetching advanced mode settings:', error));
getIsHandOffUseEnabled()
.then(handOff => {
console.debug('SettingsContext handOff:', handOff);
@ -223,7 +208,7 @@ export const SettingsProvider: React.FC<{ children: React.ReactNode }> = ({ chil
getTotalBalancePreferredUnit()
.then(unit => {
console.debug('SettingsContext totalBalancePreferredUnit:', unit);
setTotalBalancePreferredUnit(unit);
setTotalBalancePreferredUnitState(unit);
})
.catch(error => console.error('Error fetching total balance preferred unit:', error));
// eslint-disable-next-line react-hooks/exhaustive-deps
@ -250,14 +235,6 @@ export const SettingsProvider: React.FC<{ children: React.ReactNode }> = ({ chil
setLanguage(newLanguage);
}, []);
const setIsAdvancedModeEnabledStorage = useCallback(
async (value: boolean) => {
await advancedModeStorage.setItem(JSON.stringify(value));
setIsAdvancedModeEnabled(value);
},
[advancedModeStorage],
);
const setDoNotTrackStorage = useCallback(async (value: boolean) => {
await DefaultPreference.setName(GROUP_IO_BLUEWALLET);
if (value) {
@ -328,8 +305,6 @@ export const SettingsProvider: React.FC<{ children: React.ReactNode }> = ({ chil
setIsHandOffUseEnabledAsyncStorage,
isPrivacyBlurEnabled,
setIsPrivacyBlurEnabledState,
isAdvancedModeEnabled,
setIsAdvancedModeEnabledStorage,
isDoNotTrackEnabled,
setDoNotTrackStorage,
isWidgetBalanceDisplayAllowed,
@ -356,8 +331,6 @@ export const SettingsProvider: React.FC<{ children: React.ReactNode }> = ({ chil
setIsHandOffUseEnabledAsyncStorage,
isPrivacyBlurEnabled,
setIsPrivacyBlurEnabledState,
isAdvancedModeEnabled,
setIsAdvancedModeEnabledStorage,
isDoNotTrackEnabled,
setDoNotTrackStorage,
isWidgetBalanceDisplayAllowed,

View File

@ -0,0 +1,36 @@
import React from 'react';
import { InputAccessoryView, Keyboard, Platform, StyleSheet, View } from 'react-native';
import { useTheme } from './themes';
import { BlueButtonLink } from '../BlueComponents';
import loc from '../loc';
export const DismissKeyboardInputAccessoryViewID = 'DismissKeyboardInputAccessory';
export const DismissKeyboardInputAccessory: React.FC = () => {
const { colors } = useTheme();
const styleHooks = StyleSheet.create({
container: {
backgroundColor: colors.inputBackgroundColor,
},
});
if (Platform.OS !== 'ios') {
return null;
}
return (
<InputAccessoryView nativeID={DismissKeyboardInputAccessoryViewID}>
<View style={[styles.container, styleHooks.container]}>
<BlueButtonLink title={loc.send.input_done} onPress={Keyboard.dismiss} />
</View>
</InputAccessoryView>
);
};
const styles = StyleSheet.create({
container: {
flexDirection: 'row',
justifyContent: 'flex-end',
alignItems: 'center',
maxHeight: 44,
},
});

View File

@ -0,0 +1,49 @@
import React from 'react';
import { InputAccessoryView, Keyboard, Platform, StyleSheet, View } from 'react-native';
import { BlueButtonLink } from '../BlueComponents';
import loc from '../loc';
import { useTheme } from './themes';
import Clipboard from '@react-native-clipboard/clipboard';
interface DoneAndDismissKeyboardInputAccessoryProps {
onPasteTapped: (clipboard: string) => void;
onClearTapped: () => void;
}
export const DoneAndDismissKeyboardInputAccessoryViewID = 'DoneAndDismissKeyboardInputAccessory';
export const DoneAndDismissKeyboardInputAccessory: React.FC<DoneAndDismissKeyboardInputAccessoryProps> = props => {
const { colors } = useTheme();
const styleHooks = StyleSheet.create({
container: {
backgroundColor: colors.inputBackgroundColor,
},
});
const onPasteTapped = async () => {
const clipboard = await Clipboard.getString();
props.onPasteTapped(clipboard);
};
const inputView = (
<View style={[styles.container, styleHooks.container]}>
<BlueButtonLink title={loc.send.input_clear} onPress={props.onClearTapped} />
<BlueButtonLink title={loc.send.input_paste} onPress={onPasteTapped} />
<BlueButtonLink title={loc.send.input_done} onPress={Keyboard.dismiss} />
</View>
);
if (Platform.OS === 'ios') {
return <InputAccessoryView nativeID={DoneAndDismissKeyboardInputAccessoryViewID}>{inputView}</InputAccessoryView>;
} else {
return inputView;
}
};
const styles = StyleSheet.create({
container: {
flexDirection: 'row',
justifyContent: 'flex-end',
alignItems: 'center',
maxHeight: 44,
},
});

View File

@ -1,7 +1,7 @@
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import PlusIcon from './icons/PlusIcon';
import { useTheme } from './themes';
import AddWalletButton from './AddWalletButton';
interface HeaderProps {
leftText: string;
@ -25,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 onPress={onNewWalletPress} />}
{onNewWalletPress && <AddWalletButton onPress={onNewWalletPress} />}
</View>
);
};

View File

@ -1,14 +1,18 @@
import PropTypes from 'prop-types';
import React from 'react';
import { InputAccessoryView, Keyboard, Platform, StyleSheet, View } from 'react-native';
import { Text } from '@rneui/themed';
import { BlueButtonLink } from '../BlueComponents';
import loc from '../loc';
import { BitcoinUnit } from '../models/bitcoinUnits';
import { useTheme } from './themes';
const InputAccessoryAllFunds = ({ balance, canUseAll, onUseAllPressed }) => {
interface InputAccessoryAllFundsProps {
balance: string;
canUseAll: boolean;
onUseAllPressed: () => void;
}
const InputAccessoryAllFunds: React.FC<InputAccessoryAllFundsProps> = ({ balance, canUseAll, onUseAllPressed }) => {
const { colors } = useTheme();
const stylesHook = StyleSheet.create({
@ -42,7 +46,7 @@ const InputAccessoryAllFunds = ({ balance, canUseAll, onUseAllPressed }) => {
);
if (Platform.OS === 'ios') {
return <InputAccessoryView nativeID={InputAccessoryAllFunds.InputAccessoryViewID}>{inputView}</InputAccessoryView>;
return <InputAccessoryView nativeID={InputAccessoryAllFundsAccessoryViewID}>{inputView}</InputAccessoryView>;
}
// androidPlaceholder View is needed to force shrink screen (KeyboardAvoidingView) where this component is used
@ -54,13 +58,7 @@ const InputAccessoryAllFunds = ({ balance, canUseAll, onUseAllPressed }) => {
);
};
InputAccessoryAllFunds.InputAccessoryViewID = 'useMaxInputAccessoryViewID';
InputAccessoryAllFunds.propTypes = {
balance: PropTypes.string.isRequired,
canUseAll: PropTypes.bool.isRequired,
onUseAllPressed: PropTypes.func.isRequired,
};
export const InputAccessoryAllFundsAccessoryViewID = 'useMaxInputAccessoryViewID';
const styles = StyleSheet.create({
root: {

View File

@ -1,5 +1,6 @@
import React, { Ref, useCallback, useMemo } from 'react';
import { Platform, Pressable, TouchableOpacity } from 'react-native';
import { MenuView, MenuAction, NativeActionEvent } from '@react-native-menu/menu';
import {
ContextMenuView,
RenderItem,
@ -8,7 +9,6 @@ import {
IconConfig,
MenuElementConfig,
} from 'react-native-ios-context-menu';
import { MenuView, MenuAction, NativeActionEvent } from '@react-native-menu/menu';
import { ToolTipMenuProps, Action } from './types';
import { useSettings } from '../hooks/context/useSettings';
@ -30,6 +30,7 @@ const ToolTipMenu = React.memo((props: ToolTipMenuProps, ref?: Ref<any>) => {
const { language } = useSettings();
// Map Menu Items for iOS Context Menu
const mapMenuItemForContextMenuView = useCallback((action: Action) => {
if (!action.id) return null;
return {
@ -41,14 +42,30 @@ const ToolTipMenu = React.memo((props: ToolTipMenuProps, ref?: Ref<any>) => {
};
}, []);
// Map Menu Items for RN Menu (supports subactions and displayInline)
const mapMenuItemForMenuView = useCallback((action: Action): MenuAction | null => {
if (!action.id) return null;
// Check for subactions
const subactions =
action.subactions?.map(subaction => ({
id: subaction.id.toString(),
title: subaction.text,
subtitle: subaction.subtitle,
image: subaction.icon?.iconValue ? subaction.icon.iconValue : undefined,
state: subaction.menuState === undefined ? undefined : ((subaction.menuState ? 'on' : 'off') as MenuState),
attributes: { disabled: subaction.disabled, destructive: subaction.destructive, hidden: subaction.hidden },
})) || [];
return {
id: action.id.toString(),
title: action.text,
subtitle: action.subtitle,
image: action.icon?.iconValue ? action.icon.iconValue : undefined,
state: action.menuState === undefined ? undefined : ((action.menuState ? 'on' : 'off') as MenuState),
attributes: { disabled: action.disabled },
attributes: { disabled: action.disabled, destructive: action.destructive, hidden: action.hidden },
subactions: subactions.length > 0 ? subactions : undefined,
displayInline: action.displayInline || false,
};
}, []);
@ -98,7 +115,6 @@ const ToolTipMenu = React.memo((props: ToolTipMenuProps, ref?: Ref<any>) => {
);
const renderContextMenuView = () => {
console.debug('ToolTipMenu.tsx rendering: renderContextMenuView');
return (
<ContextMenuView
lazyPreview
@ -139,7 +155,6 @@ const ToolTipMenu = React.memo((props: ToolTipMenuProps, ref?: Ref<any>) => {
};
const renderMenuView = () => {
console.debug('ToolTipMenu.tsx rendering: renderMenuView');
return (
<MenuView
title={title}
@ -147,7 +162,7 @@ const ToolTipMenu = React.memo((props: ToolTipMenuProps, ref?: Ref<any>) => {
onPressAction={handlePressMenuItemForMenuView}
actions={Platform.OS === 'ios' ? menuViewItemsIOS : menuViewItemsAndroid}
shouldOpenOnLongPress={!isMenuPrimaryAction}
// @ts-ignore: its not in the types but it works
// @ts-ignore: Not exposed in types
accessibilityLabel={props.accessibilityLabel}
accessibilityHint={props.accessibilityHint}
accessibilityRole={props.accessibilityRole}

View File

@ -289,7 +289,7 @@ export const TransactionListItem: React.FC<TransactionListItemProps> = React.mem
handleOnViewOnBlockExplorer,
],
);
const toolTipActions = useMemo((): Action[] | Action[][] => {
const toolTipActions = useMemo((): Action[] => {
const actions: (Action | Action[])[] = [];
if (rowTitle !== loc.lnd.expired) {
@ -308,7 +308,7 @@ export const TransactionListItem: React.FC<TransactionListItemProps> = React.mem
actions.push([CommonToolTipActions.ExpandNote]);
}
return actions as Action[] | Action[][];
return actions as Action[];
}, [item.hash, subtitle, rowTitle, subtitleNumberOfLines]);
const accessibilityState = useMemo(() => {

View File

@ -38,13 +38,15 @@ const TransactionsNavigationHeader: React.FC<TransactionsNavigationHeaderProps>
.allowOnchainAddress()
.then((value: boolean) => setAllowOnchainAddress(value))
.catch((e: Error) => {
console.log('This Lndhub wallet does not have an onchain address API.');
console.log('This LNDhub wallet does not have an onchain address API.');
setAllowOnchainAddress(false);
});
}
}, [wallet]);
useEffect(() => {
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
setWallet(initialWallet);
}, [initialWallet]);
@ -82,9 +84,9 @@ const TransactionsNavigationHeader: React.FC<TransactionsNavigationHeaderProps>
newWalletPreferredUnit = BitcoinUnit.BTC;
}
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
const updatedWallet = updateWalletWithNewUnit(wallet, newWalletPreferredUnit);
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
setWallet(updatedWallet);
onWalletUnitChange?.(updatedWallet);
};
@ -132,8 +134,7 @@ const TransactionsNavigationHeader: React.FC<TransactionsNavigationHeaderProps>
? formatBalance(wallet.getBalance(), balanceUnit, true)
: formatBalanceWithoutSuffix(wallet.getBalance(), balanceUnit, true);
return !hideBalance && balanceFormatted;
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [wallet.hideBalance, wallet.getPreferredBalanceUnit()]);
}, [wallet]);
const toolTipWalletBalanceActions = useMemo(() => {
return wallet.hideBalance
@ -218,7 +219,7 @@ const TransactionsNavigationHeader: React.FC<TransactionsNavigationHeaderProps>
<TouchableOpacity style={styles.walletPreferredUnitView} onPress={changeWalletBalanceUnit}>
<Text style={styles.walletPreferredUnitText}>
{wallet.getPreferredBalanceUnit() === BitcoinUnit.LOCAL_CURRENCY
? preferredFiatCurrency?.endPointKey ?? FiatUnit.USD
? (preferredFiatCurrency?.endPointKey ?? FiatUnit.USD)
: wallet.getPreferredBalanceUnit()}
</Text>
</TouchableOpacity>

View File

@ -248,7 +248,7 @@ export const WalletCarouselItem: React.FC<WalletCarouselItemProps> = React.memo(
return (
<Animated.View
style={[
isLargeScreen || !horizontal ? [iStyles.rootLargeDevice, customStyle] : customStyle ?? { ...iStyles.root, width: itemWidth },
isLargeScreen || !horizontal ? [iStyles.rootLargeDevice, customStyle] : (customStyle ?? { ...iStyles.root, width: itemWidth }),
{ opacity, transform: [{ scale: scaleValue }] },
]}
>
@ -374,31 +374,27 @@ const WalletsCarousel = forwardRef<FlatListRefType, WalletsCarouselProps>((props
const flatListRef = useRef<FlatList<any>>(null);
useImperativeHandle(
ref,
(): any => {
return {
scrollToEnd: (params: { animated?: boolean | null | undefined } | undefined) => flatListRef.current?.scrollToEnd(params),
scrollToIndex: (params: {
animated?: boolean | null | undefined;
index: number;
viewOffset?: number | undefined;
viewPosition?: number | undefined;
}) => flatListRef.current?.scrollToIndex(params),
scrollToItem: (params: {
animated?: boolean | null | undefined;
item: any;
viewOffset?: number | undefined;
viewPosition?: number | undefined;
}) => flatListRef.current?.scrollToItem(params),
scrollToOffset: (params: { animated?: boolean | null | undefined; offset: number }) => flatListRef.current?.scrollToOffset(params),
recordInteraction: () => flatListRef.current?.recordInteraction(),
flashScrollIndicators: () => flatListRef.current?.flashScrollIndicators(),
getNativeScrollRef: () => flatListRef.current?.getNativeScrollRef(),
};
},
[],
);
useImperativeHandle(ref, (): any => {
return {
scrollToEnd: (params: { animated?: boolean | null | undefined } | undefined) => flatListRef.current?.scrollToEnd(params),
scrollToIndex: (params: {
animated?: boolean | null | undefined;
index: number;
viewOffset?: number | undefined;
viewPosition?: number | undefined;
}) => flatListRef.current?.scrollToIndex(params),
scrollToItem: (params: {
animated?: boolean | null | undefined;
item: any;
viewOffset?: number | undefined;
viewPosition?: number | undefined;
}) => flatListRef.current?.scrollToItem(params),
scrollToOffset: (params: { animated?: boolean | null | undefined; offset: number }) => flatListRef.current?.scrollToOffset(params),
recordInteraction: () => flatListRef.current?.recordInteraction(),
flashScrollIndicators: () => flatListRef.current?.flashScrollIndicators(),
getNativeScrollRef: () => flatListRef.current?.getNativeScrollRef(),
};
}, []);
const onScrollToIndexFailed = (error: { averageItemLength: number; index: number }): void => {
console.debug('onScrollToIndexFailed');

View File

@ -209,7 +209,7 @@ const styles = StyleSheet.create({
},
});
const getAvailableActions = ({ allowSignVerifyMessage }: { allowSignVerifyMessage: boolean }): Action[] | Action[][] => {
const getAvailableActions = ({ allowSignVerifyMessage }: { allowSignVerifyMessage: boolean }): Action[] => {
const actions = [
{
id: actionKeys.CopyToClipboard,

View File

@ -1,42 +0,0 @@
import React from 'react';
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: {
width: 30,
height: 30,
borderRadius: 15,
justifyContent: 'center',
alignContent: 'center',
} as ViewStyle,
});
const PlusIcon: React.FC<PlusIconProps> = ({ onPress }) => {
const { colors } = useTheme();
const stylesHook = StyleSheet.create({
ball: {
backgroundColor: colors.buttonBackgroundColor,
},
});
return (
<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>
);
};
export default PlusIcon;

View File

@ -1,9 +1,11 @@
import React from 'react';
import React, { useCallback, useMemo } from 'react';
import { StyleSheet, TouchableOpacity } from 'react-native';
import { Icon } from '@rneui/themed';
import { useTheme } from '../themes';
import { useExtendedNavigation } from '../../hooks/useExtendedNavigation';
import loc from '../../loc';
import ToolTipMenu from '../TooltipMenu';
import { CommonToolTipActions } from '../../typings/CommonToolTipActions';
const SettingsButton = () => {
const { colors } = useTheme();
@ -12,16 +14,32 @@ const SettingsButton = () => {
navigate('Settings');
};
const onPressMenuItem = useCallback(
(menuItem: string) => {
switch (menuItem) {
case CommonToolTipActions.ManageWallet.id:
navigate('ManageWallets');
break;
default:
break;
}
},
[navigate],
);
const actions = useMemo(() => [CommonToolTipActions.ManageWallet], []);
return (
<TouchableOpacity
accessibilityRole="button"
accessibilityLabel={loc.settings.default_title}
testID="SettingsButton"
style={[style.buttonStyle, { backgroundColor: colors.lightButton }]}
onPress={onPress}
>
<Icon size={22} name="more-horiz" type="material" color={colors.foregroundColor} />
</TouchableOpacity>
<ToolTipMenu onPressMenuItem={onPressMenuItem} actions={actions}>
<TouchableOpacity
accessibilityRole="button"
accessibilityLabel={loc.settings.default_title}
testID="SettingsButton"
style={[style.buttonStyle, { backgroundColor: colors.lightButton }]}
onPress={onPress}
>
<Icon size={22} name="more-horiz" type="material" color={colors.foregroundColor} />
</TouchableOpacity>
</ToolTipMenu>
);
};

View File

@ -1,4 +1,4 @@
import { AccessibilityRole, ViewStyle } from 'react-native';
import { AccessibilityRole, ViewStyle, ColorValue } from 'react-native';
export interface Action {
id: string | number;
@ -7,13 +7,19 @@ export interface Action {
iconValue: string;
};
menuTitle?: string;
subtitle?: string;
menuState?: 'mixed' | boolean | undefined;
displayInline?: boolean; // Indicates if subactions should be displayed inline or nested (iOS only)
image?: string;
imageColor?: ColorValue;
destructive?: boolean;
hidden?: boolean;
disabled?: boolean;
displayInline?: boolean;
subactions?: Action[]; // Nested/Inline actions (subactions) within an action
}
export interface ToolTipMenuProps {
actions: Action[] | Action[][];
actions: Action[];
children: React.ReactNode;
enableAndroidRipple?: boolean;
dismissMenu?: () => void;

View File

@ -28,116 +28,128 @@ platform :android do
end
end
desc "Update version code, build, and sign the APK"
lane :update_version_build_and_sign_apk do
Dir.chdir(project_root) do
build_number = ENV['BUILD_NUMBER']
UI.user_error!("BUILD_NUMBER environment variable is missing") if build_number.nil?
# Get the version name from build.gradle
version_name = sh("grep versionName android/app/build.gradle | awk '{print $2}' | tr -d '\"'").strip
# Get the branch name
branch_name = ENV['GITHUB_HEAD_REF'] || `git rev-parse --abbrev-ref HEAD`.strip.gsub('/', '-')
# Append branch name only if it's not 'master'
if branch_name != 'master'
signed_apk_name = "BlueWallet-#{version_name}-#{build_number}-#{branch_name}.apk"
else
signed_apk_name = "BlueWallet-#{version_name}-#{build_number}-.apk"
end
Dir.chdir("android") do
UI.message("Updating version code in build.gradle...")
gradle(
task: "assembleRelease",
properties: { "versionCode" => build_number },
project_dir: "android"
)
UI.message("Version code updated to #{build_number} and APK build completed.")
# Define the output paths
unsigned_apk_path = "app/build/outputs/apk/release/app-release-unsigned.apk"
signed_apk_path = "app/build/outputs/apk/release/#{signed_apk_name}"
# Rename the unsigned APK to include the version and build number
if File.exist?(unsigned_apk_path)
UI.message("Renaming APK to #{signed_apk_name}...")
FileUtils.mv(unsigned_apk_path, signed_apk_path)
ENV['APK_OUTPUT_PATH'] = File.expand_path(signed_apk_path)
Dir.chdir(project_root) do
build_number = ENV['BUILD_NUMBER']
UI.user_error!("BUILD_NUMBER environment variable is missing") if build_number.nil?
# Get the version name from build.gradle
version_name = sh("grep versionName android/app/build.gradle | awk '{print $2}' | tr -d '\"'").strip
# Manually update the versionCode in build.gradle
UI.message("Updating versionCode in build.gradle to #{build_number}...")
build_gradle_path = "android/app/build.gradle"
build_gradle_contents = File.read(build_gradle_path)
new_build_gradle_contents = build_gradle_contents.gsub(/versionCode\s+\d+/, "versionCode #{build_number}")
File.write(build_gradle_path, new_build_gradle_contents)
# Get the branch name and default to 'master' if empty
branch_name = ENV['GITHUB_HEAD_REF'] || `git rev-parse --abbrev-ref HEAD`.strip.gsub(/[\/\\:?*"<>|]/, '_')
if branch_name.nil? || branch_name.empty?
branch_name = 'master'
end
# Append branch name only if it's not 'master'
if branch_name != 'master'
signed_apk_name = "BlueWallet-#{version_name}-#{build_number}-#{branch_name}.apk"
else
UI.error("Unsigned APK not found at path: #{unsigned_apk_path}")
next
signed_apk_name = "BlueWallet-#{version_name}-#{build_number}.apk"
end
# Continue with the build process
Dir.chdir("android") do
UI.message("Building APK...")
gradle(
task: "assembleRelease",
project_dir: "android"
)
UI.message("APK build completed.")
# Define the output paths
unsigned_apk_path = "app/build/outputs/apk/release/app-release-unsigned.apk"
signed_apk_path = "app/build/outputs/apk/release/#{signed_apk_name}"
# Rename the unsigned APK to include the version and build number
if File.exist?(unsigned_apk_path)
UI.message("Renaming APK to #{signed_apk_name}...")
FileUtils.mv(unsigned_apk_path, signed_apk_path)
ENV['APK_OUTPUT_PATH'] = File.expand_path(signed_apk_path)
else
UI.error("Unsigned APK not found at path: #{unsigned_apk_path}")
next
end
# Sign the APK using apksigner
UI.message("Signing APK with apksigner...")
apksigner_path = "#{ENV['ANDROID_HOME']}/build-tools/34.0.0/apksigner"
sh("#{apksigner_path} sign --ks ./bluewallet-release-key.keystore --ks-pass=pass:#{ENV['KEYSTORE_PASSWORD']} #{signed_apk_path}")
UI.message("APK signed successfully: #{signed_apk_path}")
end
# Sign the APK using apksigner directly since we don't have an alias
UI.message("Signing APK with apksigner...")
apksigner_path = "#{ENV['ANDROID_HOME']}/build-tools/34.0.0/apksigner"
sh("#{apksigner_path} sign --ks ./bluewallet-release-key.keystore --ks-pass=pass:#{ENV['KEYSTORE_PASSWORD']} #{signed_apk_path}")
UI.message("APK signed successfully: #{signed_apk_path}")
end
end
end
desc "Upload APK to BrowserStack and post result as PR comment"
lane :upload_to_browserstack_and_comment do
Dir.chdir(project_root) do
# Fetch the APK path from environment variables
apk_path = ENV['APK_PATH']
# Attempt to find the APK if not provided
if apk_path.nil? || apk_path.empty?
UI.message("No APK path provided, attempting to find the artifact...")
apk_path = `find ./ -name "*.apk"`.strip
UI.user_error!("No APK file found") if apk_path.nil? || apk_path.empty?
end
UI.message("Uploading APK to BrowserStack: #{apk_path}...")
upload_to_browserstack_app_live(
file_path: apk_path,
browserstack_username: ENV['BROWSERSTACK_USERNAME'],
browserstack_access_key: ENV['BROWSERSTACK_ACCESS_KEY']
)
# Extract the BrowserStack URL from the output
app_url = ENV['BROWSERSTACK_LIVE_APP_ID']
UI.user_error!("BrowserStack upload failed, no app URL returned") if app_url.nil? || app_url.empty?
# Prepare necessary values for the PR comment
apk_filename = File.basename(apk_path)
browserstack_hashed_id = app_url.gsub('bs://', '')
pr_number = ENV['GITHUB_PR_NUMBER']
comment = <<~COMMENT
### APK Successfully Uploaded to BrowserStack
You can test it on the following devices:
- [Google Pixel 5 (Android 12.0)](https://app-live.browserstack.com/dashboard#os=android&os_version=12.0&device=Google+Pixel+5&app_hashed_id=#{browserstack_hashed_id}&scale_to_fit=true&speed=1&start=true)
- [Google Pixel 7 (Android 13.0)](https://app-live.browserstack.com/dashboard#os=android&os_version=13.0&device=Google+Pixel+7&app_hashed_id=#{browserstack_hashed_id}&scale_to_fit=true&speed=1&start=true)
- [Google Pixel 8 (Android 14.0)](https://app-live.browserstack.com/dashboard#os=android&os_version=14.0&device=Google+Pixel+8&app_hashed_id=#{browserstack_hashed_id}&scale_to_fit=true&speed=1&start=true)
- [Samsung Galaxy Z Fold 5 (Android 13.0)](https://app-live.browserstack.com/dashboard#os=android&os_version=13.0&device=Samsung+Galaxy+Z+Fold+5&app_hashed_id=#{browserstack_hashed_id}&scale_to_fit=true&speed=1&start=true)
- [Samsung Galaxy Z Fold 6 (Android 14.0)](https://app-live.browserstack.com/dashboard#os=android&os_version=14.0&device=Samsung+Galaxy+Z+Fold+6&app_hashed_id=#{browserstack_hashed_id}&scale_to_fit=true&speed=1&start=true)
- [Samsung Galaxy Tab S9 (Android 13.0)](https://app-live.browserstack.com/dashboard#os=android&os_version=13.0&device=Samsung+Galaxy+Tab+S9&app_hashed_id=#{browserstack_hashed_id}&scale_to_fit=true&speed=1&start=true)
**Filename**: #{apk_filename}
**BrowserStack App URL**: #{app_url}
COMMENT
if pr_number
begin
sh("GH_TOKEN=#{ENV['GH_TOKEN']} gh pr comment #{pr_number} --body '#{comment}'")
UI.success("Posted comment to PR ##{pr_number}")
rescue => e
UI.error("Failed to post comment to PR: #{e.message}")
desc "Upload APK to BrowserStack and post result as PR comment"
lane :upload_to_browserstack_and_comment do
Dir.chdir(project_root) do
# Fetch the APK path from environment variables
apk_path = ENV['APK_PATH']
# Attempt to find the APK if not provided
if apk_path.nil? || apk_path.empty?
UI.message("No APK path provided, attempting to find the artifact...")
apk_path = `find ./ -name "*.apk"`.strip
UI.user_error!("No APK file found") if apk_path.nil? || apk_path.empty?
end
UI.message("Uploading APK to BrowserStack: #{apk_path}...")
upload_to_browserstack_app_live(
file_path: apk_path,
browserstack_username: ENV['BROWSERSTACK_USERNAME'],
browserstack_access_key: ENV['BROWSERSTACK_ACCESS_KEY']
)
# Extract the BrowserStack URL from the output
app_url = ENV['BROWSERSTACK_LIVE_APP_ID']
UI.user_error!("BrowserStack upload failed, no app URL returned") if app_url.nil? || app_url.empty?
# Prepare necessary values for the PR comment
apk_filename = File.basename(apk_path)
apk_download_url = ENV['APK_OUTPUT_PATH'] # Assuming this path is accessible to the PR
browserstack_hashed_id = app_url.gsub('bs://', '')
pr_number = ENV['GITHUB_PR_NUMBER']
comment = <<~COMMENT
### APK Successfully Uploaded to BrowserStack
You can test it on the following devices:
- [Google Pixel 5 (Android 12.0)](https://app-live.browserstack.com/dashboard#os=android&os_version=12.0&device=Google+Pixel+5&app_hashed_id=#{browserstack_hashed_id}&scale_to_fit=true&speed=1&start=true)
- [Google Pixel 7 (Android 13.0)](https://app-live.browserstack.com/dashboard#os=android&os_version=13.0&device=Google+Pixel+7&app_hashed_id=#{browserstack_hashed_id}&scale_to_fit=true&speed=1&start=true)
- [Google Pixel 8 (Android 14.0)](https://app-live.browserstack.com/dashboard#os=android&os_version=14.0&device=Google+Pixel+8&app_hashed_id=#{browserstack_hashed_id}&scale_to_fit=true&speed=1&start=true)
- [Google Pixel 3a (Android 9.0)](https://app-live.browserstack.com/dashboard#os=android&os_version=9.0&device=Google+Pixel+3a&app_hashed_id=#{browserstack_hashed_id}&scale_to_fit=true&speed=1&start=true)
- [Samsung Galaxy Z Fold 5 (Android 13.0)](https://app-live.browserstack.com/dashboard#os=android&os_version=13.0&device=Samsung+Galaxy+Z+Fold+5&app_hashed_id=#{browserstack_hashed_id}&scale_to_fit=true&speed=1&start=true)
- [Samsung Galaxy Z Fold 6 (Android 14.0)](https://app-live.browserstack.com/dashboard#os=android&os_version=14.0&device=Samsung+Galaxy+Z+Fold+6&app_hashed_id=#{browserstack_hashed_id}&scale_to_fit=true&speed=1&start=true)
- [Samsung Galaxy Tab S9 (Android 13.0)](https://app-live.browserstack.com/dashboard#os=android&os_version=13.0&device=Samsung+Galaxy+Tab+S9&app_hashed_id=#{browserstack_hashed_id}&scale_to_fit=true&speed=1&start=true)
- [Samsung Galaxy Note 9 (Android 8.1)](https://app-live.browserstack.com/dashboard#os=android&os_version=8.1&device=Samsung+Galaxy+Note+9&app_hashed_id=#{browserstack_hashed_id}&scale_to_fit=true&speed=1&start=true)
**Filename**: [#{apk_filename}](#{apk_download_url})
**BrowserStack App URL**: #{app_url}
COMMENT
if pr_number
begin
sh("GH_TOKEN=#{ENV['GH_TOKEN']} gh pr comment #{pr_number} --body '#{comment}'")
UI.success("Posted comment to PR ##{pr_number}")
rescue => e
UI.error("Failed to post comment to PR: #{e.message}")
end
else
UI.important("No PR number found. Skipping PR comment.")
end
else
UI.important("No PR number found. Skipping PR comment.")
end
end
end
end
platform :ios do
@ -167,7 +179,8 @@ platform :ios do
type: "development",
app_identifier: app_identifier,
readonly: false, # This will regenerate the provisioning profile if needed
force_for_new_devices: true # This forces match to add new devices to the profile
force_for_new_devices: true,
clone_branch_directly: true
)
end
@ -211,6 +224,7 @@ platform :ios do
git_basic_authorization: ENV["GIT_ACCESS_TOKEN"],
git_url: ENV["GIT_URL"],
type: "appstore",
clone_branch_directly: true, # Skip if the branch already exists (Exit 128 error)
platform: platform,
app_identifier: app_identifier,
team_id: ENV["ITC_TEAM_ID"],
@ -228,7 +242,8 @@ platform :ios do
type: "development",
platform: "catalyst",
app_identifier: app_identifiers,
readonly: true
readonly: true,
clone_branch_directly: true
)
end
@ -238,7 +253,9 @@ platform :ios do
type: "appstore",
platform: "catalyst",
app_identifier: app_identifiers,
readonly: true
readonly: true,
clone_branch_directly: true
)
end
@ -250,14 +267,16 @@ platform :ios do
platform: "catalyst",
app_identifier: app_identifier,
readonly: false,
force_for_new_devices: true
force_for_new_devices: true,
clone_branch_directly: true
)
match(
type: "appstore",
platform: "catalyst",
app_identifier: app_identifier,
readonly: false
readonly: false,
clone_branch_directly: true
)
end
end
@ -326,8 +345,8 @@ platform :ios do
changelog = ENV["LATEST_COMMIT_MESSAGE"]
upload_to_testflight(
api_key_path: "appstore_api_key.json",
ipa: "./build/BlueWallet.#{ENV['PROJECT_VERSION']}(#{ENV['NEW_BUILD_NUMBER']}).ipa",
api_key_path: "./appstore_api_key.json",
ipa: "./BlueWallet.#{ENV['PROJECT_VERSION']}(#{ENV['NEW_BUILD_NUMBER']}).ipa",
skip_waiting_for_build_processing: true, # Do not wait for processing
changelog: changelog
)

View File

@ -9,6 +9,7 @@
/* Begin PBXBuildFile section */
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
17CDA0718F42DB2CE856C872 /* libPods-BlueWallet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 040819EDF8BD9C50A9C83E24 /* libPods-BlueWallet.a */; };
32B5A32A2334450100F8D608 /* Bridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32B5A3292334450100F8D608 /* Bridge.swift */; };
32F0A29A2311DBB20095C559 /* ComplicationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32F0A2992311DBB20095C559 /* ComplicationController.swift */; };
6D2A6464258BA92D0092292B /* Stickers.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6D2A6463258BA92D0092292B /* Stickers.xcassets */; };
@ -42,7 +43,6 @@
6DFC807024EA0B6C007B8700 /* EFQRCode in Frameworks */ = {isa = PBXBuildFile; productRef = 6DFC806F24EA0B6C007B8700 /* EFQRCode */; };
6DFC807224EA2FA9007B8700 /* ViewQRCodefaceController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DFC807124EA2FA9007B8700 /* ViewQRCodefaceController.swift */; };
764B49B1420D4AEB8109BF62 /* libsqlite3.0.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B468CC34D5B41F3950078EF /* libsqlite3.0.tbd */; };
773E382FE62E836172AAB98B /* libPods-BlueWallet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 95304AD151F1F531985AA341 /* libPods-BlueWallet.a */; };
782F075B5DD048449E2DECE9 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = B9D9B3A7B2CB4255876B67AF /* libz.tbd */; };
849047CA2702A32A008EE567 /* Handoff.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849047C92702A32A008EE567 /* Handoff.swift */; };
84E05A842721191B001A0D3A /* Settings.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 84E05A832721191B001A0D3A /* Settings.bundle */; };
@ -212,11 +212,12 @@
/* Begin PBXFileReference section */
008F07F21AC5B25A0029DE68 /* main.jsbundle */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = main.jsbundle; sourceTree = "<group>"; };
00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
0C3D27CE367C0DD11F4B8772 /* Pods-BlueWalletUITests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-BlueWalletUITests.release.xcconfig"; path = "Target Support Files/Pods-BlueWalletUITests/Pods-BlueWalletUITests.release.xcconfig"; sourceTree = "<group>"; };
040819EDF8BD9C50A9C83E24 /* libPods-BlueWallet.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-BlueWallet.a"; sourceTree = BUILT_PRODUCTS_DIR; };
13B07F961A680F5B00A75B9A /* BlueWallet.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = BlueWallet.app; sourceTree = BUILT_PRODUCTS_DIR; };
13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = BlueWallet/Images.xcassets; sourceTree = "<group>"; };
13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = BlueWallet/Info.plist; sourceTree = "<group>"; };
13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = BlueWallet/main.m; sourceTree = "<group>"; };
1AE7FA8B4A18928E917F42D1 /* Pods-BlueWallet.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-BlueWallet.debug.xcconfig"; path = "Target Support Files/Pods-BlueWallet/Pods-BlueWallet.debug.xcconfig"; sourceTree = "<group>"; };
1DD63E4B5C8344BB9880C9EC /* libReactNativePermissions.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libReactNativePermissions.a; sourceTree = "<group>"; };
253243E162CE4822BF3A3B7D /* libRNRandomBytes-tvOS.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = "libRNRandomBytes-tvOS.a"; sourceTree = "<group>"; };
2654894D4DE44A4C8F71773D /* CoreData.framework */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; };
@ -288,11 +289,8 @@
6DEB4C3A254FBF4800E9F9AA /* Colors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Colors.swift; sourceTree = "<group>"; };
6DF25A9E249DB97E001D06F5 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = "<group>"; };
6DFC807124EA2FA9007B8700 /* ViewQRCodefaceController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewQRCodefaceController.swift; sourceTree = "<group>"; };
6E8A234AFCA1624321AE54F5 /* Pods-BlueWalletUITests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-BlueWalletUITests.debug.xcconfig"; path = "Target Support Files/Pods-BlueWalletUITests/Pods-BlueWalletUITests.debug.xcconfig"; sourceTree = "<group>"; };
6EB3338E347F4AFAA8C85C04 /* libRNDeviceInfo-tvOS.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = "libRNDeviceInfo-tvOS.a"; sourceTree = "<group>"; };
6F02C2F7CA3591E4E0B06EBA /* libPods-BlueWalletUITests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-BlueWalletUITests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
70C9C17A3F52430B99582AF4 /* libRNCamera.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNCamera.a; sourceTree = "<group>"; };
77ED97C3CA4284744868B15D /* Pods-BlueWallet.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-BlueWallet.release.xcconfig"; path = "Target Support Files/Pods-BlueWallet/Pods-BlueWallet.release.xcconfig"; sourceTree = "<group>"; };
78A87E7251D94144A71A2F67 /* FontAwesome5_Solid.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = FontAwesome5_Solid.ttf; path = "../node_modules/react-native-vector-icons/Fonts/FontAwesome5_Solid.ttf"; sourceTree = "<group>"; };
7B468CC34D5B41F3950078EF /* libsqlite3.0.tbd */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libsqlite3.0.tbd; path = usr/lib/libsqlite3.0.tbd; sourceTree = SDKROOT; };
8448882949434D41A054C0B2 /* ToolTipMenuTests.xctest */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = wrapper.cfbundle; path = ToolTipMenuTests.xctest; sourceTree = "<group>"; };
@ -300,9 +298,9 @@
84E05A832721191B001A0D3A /* Settings.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = Settings.bundle; sourceTree = "<group>"; };
8637D4B5E14D443A9031DA95 /* libRNFS.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNFS.a; sourceTree = "<group>"; };
90F86BC5194548CA87D729A9 /* libToolTipMenu.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libToolTipMenu.a; sourceTree = "<group>"; };
93D74F9C8EE7B4443A49594C /* Pods-BlueWallet.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-BlueWallet.release.xcconfig"; path = "Target Support Files/Pods-BlueWallet/Pods-BlueWallet.release.xcconfig"; sourceTree = "<group>"; };
94565BFC6A0C4235B3EC7B01 /* libRNSVG.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNSVG.a; sourceTree = "<group>"; };
95208B2A05884A76B5BB99C0 /* libRCTGoogleAnalyticsBridge.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRCTGoogleAnalyticsBridge.a; sourceTree = "<group>"; };
95304AD151F1F531985AA341 /* libPods-BlueWallet.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-BlueWallet.a"; sourceTree = BUILT_PRODUCTS_DIR; };
9DF4E6C040764E4BA1ACC1EB /* libTcpSockets.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libTcpSockets.a; sourceTree = "<group>"; };
9F1F51A83D044F3BB26A35FC /* libRNSVG-tvOS.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = "libRNSVG-tvOS.a"; sourceTree = "<group>"; };
A7C4B1FDAD264618BAF8C335 /* libRNCWebView.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNCWebView.a; sourceTree = "<group>"; };
@ -361,7 +359,6 @@
B4D3235A177F4580BA52F2F9 /* libRNCSlider.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNCSlider.a; sourceTree = "<group>"; };
B4EFF73A2C3F6C5E0095D655 /* MockData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockData.swift; sourceTree = "<group>"; };
B642AFB13483418CAB6FF25E /* libRCTQRCodeLocalImage.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRCTQRCodeLocalImage.a; sourceTree = "<group>"; };
B68F8552DD4428F64B11DCFB /* Pods-BlueWallet.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-BlueWallet.debug.xcconfig"; path = "Target Support Files/Pods-BlueWallet/Pods-BlueWallet.debug.xcconfig"; sourceTree = "<group>"; };
B9D9B3A7B2CB4255876B67AF /* libz.tbd */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; };
BBA99996E6FA4B49ACE0BEFA /* libRNRate.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNRate.a; sourceTree = "<group>"; };
CA741BA794714D3F80251AC9 /* Ionicons.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = Ionicons.ttf; path = "../node_modules/react-native-vector-icons/Fonts/Ionicons.ttf"; sourceTree = "<group>"; };
@ -385,7 +382,7 @@
782F075B5DD048449E2DECE9 /* libz.tbd in Frameworks */,
764B49B1420D4AEB8109BF62 /* libsqlite3.0.tbd in Frameworks */,
C978A716948AB7DEC5B6F677 /* BuildFile in Frameworks */,
773E382FE62E836172AAB98B /* libPods-BlueWallet.a in Frameworks */,
17CDA0718F42DB2CE856C872 /* libPods-BlueWallet.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -480,8 +477,7 @@
3271B0AA236E2E0700DA766F /* NotificationCenter.framework */,
6D333B3A252FE1A3004D72DF /* WidgetKit.framework */,
6D333B3C252FE1A3004D72DF /* SwiftUI.framework */,
95304AD151F1F531985AA341 /* libPods-BlueWallet.a */,
6F02C2F7CA3591E4E0B06EBA /* libPods-BlueWalletUITests.a */,
040819EDF8BD9C50A9C83E24 /* libPods-BlueWallet.a */,
);
name = Frameworks;
sourceTree = "<group>";
@ -778,10 +774,8 @@
FAA856B639C61E61D2CF90A8 /* Pods */ = {
isa = PBXGroup;
children = (
B68F8552DD4428F64B11DCFB /* Pods-BlueWallet.debug.xcconfig */,
77ED97C3CA4284744868B15D /* Pods-BlueWallet.release.xcconfig */,
6E8A234AFCA1624321AE54F5 /* Pods-BlueWalletUITests.debug.xcconfig */,
0C3D27CE367C0DD11F4B8772 /* Pods-BlueWalletUITests.release.xcconfig */,
1AE7FA8B4A18928E917F42D1 /* Pods-BlueWallet.debug.xcconfig */,
93D74F9C8EE7B4443A49594C /* Pods-BlueWallet.release.xcconfig */,
);
path = Pods;
sourceTree = "<group>";
@ -793,7 +787,7 @@
isa = PBXNativeTarget;
buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "BlueWallet" */;
buildPhases = (
3018134BCE2C10C2242F4CA3 /* [CP] Check Pods Manifest.lock */,
3B467A525D105B531AB91B81 /* [CP] Check Pods Manifest.lock */,
13B07F871A680F5B00A75B9A /* Sources */,
13B07F8C1A680F5B00A75B9A /* Frameworks */,
13B07F8E1A680F5B00A75B9A /* Resources */,
@ -802,8 +796,8 @@
3271B0B6236E2E0700DA766F /* Embed App Extensions */,
A8D9893AE3CD454A9094B651 /* Upload source maps to Bugsnag */,
4B36CFF6FE55027DCA5CB6E1 /* Upload Bugsnag dSYM */,
1D93562AB5DF61839917DB14 /* [CP] Embed Pods Frameworks */,
4D8F1D9E38ABBC60EA8546DF /* [CP] Copy Pods Resources */,
BFE56A9A22A21E360BF7A1EC /* [CP] Embed Pods Frameworks */,
D0E81659D2FBFDD27024CF05 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@ -1049,26 +1043,9 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "export EXTRA_PACKAGER_ARGS=\"--sourcemap-output $TMPDIR/$(md5 -qs \"$CONFIGURATION_BUILD_DIR\")-main.jsbundle.map\"\nexport NODE_BINARY=node\n../node_modules/react-native/scripts/react-native-xcode.sh\n";
shellScript = "export EXTRA_PACKAGER_ARGS=\"--sourcemap-output $TMPDIR/$(md5 -qs \"$CONFIGURATION_BUILD_DIR\")-main.jsbundle.map\"\nexport NODE_BINARY=$(which node)\n../node_modules/react-native/scripts/react-native-xcode.sh\n";
};
1D93562AB5DF61839917DB14 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-BlueWallet/Pods-BlueWallet-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-BlueWallet/Pods-BlueWallet-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-BlueWallet/Pods-BlueWallet-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
3018134BCE2C10C2242F4CA3 /* [CP] Check Pods Manifest.lock */ = {
3B467A525D105B531AB91B81 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@ -1111,23 +1088,6 @@
shellScript = "api_key = nil # Insert your key here to use it directly from this script\n\n# Attempt to get the API key from an environment variable\nunless api_key\n api_key = ENV[\"BUGSNAG_API_KEY\"]\n\n # If not present, attempt to lookup the value from the Info.plist\n unless api_key\n info_plist_path = \"#{ENV[\"BUILT_PRODUCTS_DIR\"]}/#{ENV[\"INFOPLIST_PATH\"]}\"\n plist_buddy_response = `/usr/libexec/PlistBuddy -c \"print :bugsnag:apiKey\" \"#{info_plist_path}\"`\n plist_buddy_response = `/usr/libexec/PlistBuddy -c \"print :BugsnagAPIKey\" \"#{info_plist_path}\"` if !$?.success?\n api_key = plist_buddy_response if $?.success?\n end\nend\n\nfail(\"No Bugsnag API key detected - add your key to your Info.plist, BUGSNAG_API_KEY environment variable or this Run Script phase\") unless api_key\n\nfork do\n Process.setsid\n STDIN.reopen(\"/dev/null\")\n STDOUT.reopen(\"/dev/null\", \"a\")\n STDERR.reopen(\"/dev/null\", \"a\")\n\n require 'shellwords'\n\n Dir[\"#{ENV[\"DWARF_DSYM_FOLDER_PATH\"]}/*/Contents/Resources/DWARF/*\"].each do |dsym|\n curl_command = \"curl --http1.1 -F dsym=@#{Shellwords.escape(dsym)} -F projectRoot=#{Shellwords.escape(ENV[\"PROJECT_DIR\"])} \"\n curl_command += \"-F apiKey=#{Shellwords.escape(api_key)} \"\n curl_command += \"https://upload.bugsnag.com/\"\n system(curl_command)\n end\nend\n";
showEnvVarsInLog = 0;
};
4D8F1D9E38ABBC60EA8546DF /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-BlueWallet/Pods-BlueWallet-resources-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Copy Pods Resources";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-BlueWallet/Pods-BlueWallet-resources-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-BlueWallet/Pods-BlueWallet-resources.sh\"\n";
showEnvVarsInLog = 0;
};
A8D9893AE3CD454A9094B651 /* Upload source maps to Bugsnag */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
@ -1142,6 +1102,23 @@
shellPath = /bin/sh;
shellScript = "SOURCE_MAP=\"$TMPDIR/$(md5 -qs \"$CONFIGURATION_BUILD_DIR\")-main.jsbundle.map\" ../node_modules/@bugsnag/react-native/bugsnag-react-native-xcode.sh\n";
};
BFE56A9A22A21E360BF7A1EC /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-BlueWallet/Pods-BlueWallet-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-BlueWallet/Pods-BlueWallet-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-BlueWallet/Pods-BlueWallet-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
CF0725821442A3000F20E874 /* Upload Bugsnag dSYM */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
@ -1163,6 +1140,23 @@
shellScript = "api_key = nil # Insert your key here to use it directly from this script\n\n# Attempt to get the API key from an environment variable\nunless api_key\n api_key = ENV[\"BUGSNAG_API_KEY\"]\n\n # If not present, attempt to lookup the value from the Info.plist\n unless api_key\n info_plist_path = \"#{ENV[\"BUILT_PRODUCTS_DIR\"]}/#{ENV[\"INFOPLIST_PATH\"]}\"\n plist_buddy_response = `/usr/libexec/PlistBuddy -c \"print :bugsnag:apiKey\" \"#{info_plist_path}\"`\n plist_buddy_response = `/usr/libexec/PlistBuddy -c \"print :BugsnagAPIKey\" \"#{info_plist_path}\"` if !$?.success?\n api_key = plist_buddy_response if $?.success?\n end\nend\n\nfail(\"No Bugsnag API key detected - add your key to your Info.plist, BUGSNAG_API_KEY environment variable or this Run Script phase\") unless api_key\n\nfork do\n Process.setsid\n STDIN.reopen(\"/dev/null\")\n STDOUT.reopen(\"/dev/null\", \"a\")\n STDERR.reopen(\"/dev/null\", \"a\")\n\n require 'shellwords'\n\n Dir[\"#{ENV[\"DWARF_DSYM_FOLDER_PATH\"]}/*/Contents/Resources/DWARF/*\"].each do |dsym|\n curl_command = \"curl --http1.1 -F dsym=@#{Shellwords.escape(dsym)} -F projectRoot=#{Shellwords.escape(ENV[\"PROJECT_DIR\"])} \"\n curl_command += \"-F apiKey=#{Shellwords.escape(api_key)} \"\n curl_command += \"https://upload.bugsnag.com/\"\n system(curl_command)\n end\nend\n";
showEnvVarsInLog = 0;
};
D0E81659D2FBFDD27024CF05 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-BlueWallet/Pods-BlueWallet-resources-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Copy Pods Resources";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-BlueWallet/Pods-BlueWallet-resources-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-BlueWallet/Pods-BlueWallet-resources.sh\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
@ -1351,7 +1345,7 @@
/* Begin XCBuildConfiguration section */
13B07F941A680F5B00A75B9A /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = B68F8552DD4428F64B11DCFB /* Pods-BlueWallet.debug.xcconfig */;
baseConfigurationReference = 1AE7FA8B4A18928E917F42D1 /* Pods-BlueWallet.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
@ -1360,7 +1354,7 @@
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 1703136697;
CURRENT_PROJECT_VERSION = 1703136699;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = A7W54YZ4WU;
@ -1385,7 +1379,7 @@
"$(SDKROOT)/System/iOSSupport/usr/lib/swift",
"$(inherited)",
);
MARKETING_VERSION = 7.0.4;
MARKETING_VERSION = 7.0.5;
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
@ -1411,7 +1405,7 @@
};
13B07F951A680F5B00A75B9A /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 77ED97C3CA4284744868B15D /* Pods-BlueWallet.release.xcconfig */;
baseConfigurationReference = 93D74F9C8EE7B4443A49594C /* Pods-BlueWallet.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
@ -1420,7 +1414,7 @@
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Distribution";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 1703136697;
CURRENT_PROJECT_VERSION = 1703136699;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = A7W54YZ4WU;
@ -1440,7 +1434,7 @@
"$(SDKROOT)/System/iOSSupport/usr/lib/swift",
"$(inherited)",
);
MARKETING_VERSION = 7.0.4;
MARKETING_VERSION = 7.0.5;
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
@ -1476,7 +1470,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 1703136697;
CURRENT_PROJECT_VERSION = 1703136699;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = "";
@ -1489,7 +1483,7 @@
"$(SDKROOT)/System/iOSSupport/usr/lib/swift",
"$(inherited)",
);
MARKETING_VERSION = 7.0.4;
MARKETING_VERSION = 7.0.5;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
PRESERVE_DEAD_CODE_INITS_AND_TERMS = YES;
@ -1519,7 +1513,7 @@
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1703136697;
CURRENT_PROJECT_VERSION = 1703136699;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = "";
@ -1532,7 +1526,7 @@
"$(SDKROOT)/System/iOSSupport/usr/lib/swift",
"$(inherited)",
);
MARKETING_VERSION = 7.0.4;
MARKETING_VERSION = 7.0.5;
MTL_FAST_MATH = YES;
PRESERVE_DEAD_CODE_INITS_AND_TERMS = YES;
PRODUCT_BUNDLE_IDENTIFIER = io.bluewallet.bluewallet.Stickers;
@ -1563,7 +1557,7 @@
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 1703136697;
CURRENT_PROJECT_VERSION = 1703136699;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = "";
@ -1582,7 +1576,7 @@
"$(SDKROOT)/System/iOSSupport/usr/lib/swift",
"$(inherited)",
);
MARKETING_VERSION = 7.0.4;
MARKETING_VERSION = 7.0.5;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
PRESERVE_DEAD_CODE_INITS_AND_TERMS = YES;
@ -1619,7 +1613,7 @@
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Distribution";
CODE_SIGN_STYLE = Manual;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1703136697;
CURRENT_PROJECT_VERSION = 1703136699;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = "";
@ -1638,7 +1632,7 @@
"$(SDKROOT)/System/iOSSupport/usr/lib/swift",
"$(inherited)",
);
MARKETING_VERSION = 7.0.4;
MARKETING_VERSION = 7.0.5;
MTL_FAST_MATH = YES;
PRESERVE_DEAD_CODE_INITS_AND_TERMS = YES;
PRODUCT_BUNDLE_IDENTIFIER = io.bluewallet.bluewallet.MarketWidget;
@ -1707,7 +1701,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 11.2;
IPHONEOS_DEPLOYMENT_TARGET = 13.4;
LD = "";
LDPLUSPLUS = "";
LIBRARY_SEARCH_PATHS = "$(SDKROOT)/usr/lib/swift\"$(inherited)\"";
@ -1721,6 +1715,7 @@
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) DEBUG";
SWIFT_VERSION = 5.0;
USE_HERMES = true;
WATCHOS_DEPLOYMENT_TARGET = 7.0;
};
name = Debug;
};
@ -1771,7 +1766,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 11.2;
IPHONEOS_DEPLOYMENT_TARGET = 13.4;
LD = "";
LDPLUSPLUS = "";
LIBRARY_SEARCH_PATHS = "$(SDKROOT)/usr/lib/swift\"$(inherited)\"";
@ -1785,6 +1780,7 @@
SWIFT_VERSION = 5.0;
USE_HERMES = true;
VALIDATE_PRODUCT = YES;
WATCHOS_DEPLOYMENT_TARGET = 7.0;
};
name = Release;
};
@ -1802,7 +1798,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=watchos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 1703136697;
CURRENT_PROJECT_VERSION = 1703136699;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = "";
@ -1819,7 +1815,7 @@
"$(SDKROOT)/System/iOSSupport/usr/lib/swift",
"$(inherited)",
);
MARKETING_VERSION = 7.0.4;
MARKETING_VERSION = 7.0.5;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
PRESERVE_DEAD_CODE_INITS_AND_TERMS = YES;
@ -1852,7 +1848,7 @@
"CODE_SIGN_IDENTITY[sdk=watchos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1703136697;
CURRENT_PROJECT_VERSION = 1703136699;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = "";
@ -1869,7 +1865,7 @@
"$(SDKROOT)/System/iOSSupport/usr/lib/swift",
"$(inherited)",
);
MARKETING_VERSION = 7.0.4;
MARKETING_VERSION = 7.0.5;
MTL_FAST_MATH = YES;
PRESERVE_DEAD_CODE_INITS_AND_TERMS = YES;
PRODUCT_BUNDLE_IDENTIFIER = io.bluewallet.bluewallet.watch.extension;
@ -1901,7 +1897,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=watchos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 1703136697;
CURRENT_PROJECT_VERSION = 1703136699;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = "";
@ -1914,7 +1910,7 @@
"$(SDKROOT)/System/iOSSupport/usr/lib/swift",
"$(inherited)",
);
MARKETING_VERSION = 7.0.4;
MARKETING_VERSION = 7.0.5;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
PRESERVE_DEAD_CODE_INITS_AND_TERMS = YES;
@ -1949,7 +1945,7 @@
"CODE_SIGN_IDENTITY[sdk=watchos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1703136697;
CURRENT_PROJECT_VERSION = 1703136699;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = "";
@ -1962,7 +1958,7 @@
"$(SDKROOT)/System/iOSSupport/usr/lib/swift",
"$(inherited)",
);
MARKETING_VERSION = 7.0.4;
MARKETING_VERSION = 7.0.5;
MTL_FAST_MATH = YES;
PRESERVE_DEAD_CODE_INITS_AND_TERMS = YES;
PRODUCT_BUNDLE_IDENTIFIER = io.bluewallet.bluewallet.watch;

View File

@ -58,18 +58,6 @@
<string>io.bluewallet.backup</string>
</array>
</dict>
<dict>
<key>CFBundleTypeName</key>
<string>JSON File</string>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>LSHandlerRank</key>
<string>Owner</string>
<key>LSItemContentTypes</key>
<array>
<string>public.json</string>
</array>
</dict>
<dict>
<key>CFBundleTypeIconFiles</key>
<array/>
@ -239,10 +227,6 @@
</dict>
</dict>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.json</string>
</array>
<key>UTTypeDescription</key>
<string>BW COSIGNER</string>
<key>UTTypeIconFiles</key>
@ -288,8 +272,6 @@
<string>JSON File</string>
<key>UTTypeIconFiles</key>
<array/>
<key>UTTypeIdentifier</key>
<string>public.json</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
@ -360,10 +342,6 @@
</dict>
</dict>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.json</string>
</array>
<key>UTTypeDescription</key>
<string>BW COSIGNER</string>
<key>UTTypeIconFiles</key>

View File

@ -19,7 +19,6 @@ 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'])
@ -56,6 +55,7 @@ post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '13.4'
if ['React-Core-AccessibilityResources'].include? target.name
config.build_settings['CODE_SIGN_STYLE'] = "Manual"
config.build_settings['CODE_SIGN_IDENTITY'] = "Apple Distribution: Bluewallet Services, S. R. L. (A7W54YZ4WU)"

File diff suppressed because it is too large Load Diff

View File

@ -22,9 +22,10 @@ export CPPFLAGS="-I/usr/local/opt/node@20/include"
echo "Configuration complete."
# Install dependencies using npm
echo "===== Running npm install ====="
npm install -y | tee npm-install-log.txt
echo "npm install complete. Full log output in npm-install-log.txt"
echo "===== Running npm ci ====="
npm ci | tee npm-ci-log.txt
npm prune --production | tee npm-prune-log.txt
echo "npm ci complete. Full log output in npm-ci-log.txt and npm-prune-log.txt"
echo "===== Running pod install ====="
cd ios

View File

@ -221,7 +221,7 @@
"use_ssl": "استخدم SSL",
"electrum_saved": "تم حفظ تغييراتك بنجاح. قد تحتاج إلى إعادة التشغيل لتصبح التغييرات سارية المفعول.",
"set_electrum_server_as_default": "هل تريد تعيين {server} كخادم Electrum الافتراضي؟",
"set_lndhub_as_default": "هل تريد تعيين {url} كخادم LNDHub الافتراضي؟",
"set_lndhub_as_default": "هل تريد تعيين {url} كخادم LNDhub الافتراضي؟",
"electrum_settings_server": "خادم Electrum",
"electrum_settings_explain": "اتركه فارغا لاستخدام الاعدادات الافتراضية.",
"electrum_status": "الحالة",
@ -244,7 +244,7 @@
"encrypt_use_expl": "سيتم استخدام {type} لتأكيد هويتك قبل إجراء معاملة أو فتح محفظة أو تصديرها أو حذفها. ولن يتم استخدام {type} لفتح وحدة تخزين مشفرة.",
"general": "عام",
"general_adv_mode": "الوضع المتقدم",
"general_adv_mode_e": "عند تمكين هذا الإعداد، سترى خيارات متقدمة أثناء إنشاء المحفظة، مثل أنواع محافظ مختلفة، القدرة على الاتصال ب LNDHub محدد، وإنتروبيا (عشوائية) مخصصة.",
"general_adv_mode_e": "عند تمكين هذا الإعداد، سترى خيارات متقدمة أثناء إنشاء المحفظة، مثل أنواع محافظ مختلفة، القدرة على الاتصال ب LNDhub محدد، وإنتروبيا (عشوائية) مخصصة.",
"general_continuity": "الاتساق",
"general_continuity_e": "عند تمكين هذا الإعداد، ستتمكن من عرض المحافظ والعمليات المحدَّدة باستخدام أجهزتك الأخرى المتصلة بنفس حساب Apple iCloud.",
"groundcontrol_explanation": "GroundControl هو خادم إشعارات فورية مجاني مفتوح المصدر لمحافظ البتكوين. يمكنك تثبيت خادم GroundControl الخاص بك ووضع عنوان (URL) له هنا لعدم الاعتماد على البنية التحتية لمحفظة BlueWallet. اترك الحقل فارغًا لاستخدام الإعدادات الافتراضية",
@ -252,10 +252,10 @@
"language": "اللغة",
"last_updated": "آخر تحديث",
"language_isRTL": "يجب اعادة تشغيل BlueWallet حتى تظهر تعديلات تغيير اللغة.",
"lightning_error_lndhub_uri": "معرِّف URI لبرنامج تضمين LndHub غير صالح",
"lightning_error_lndhub_uri": "معرِّف URI لبرنامج تضمين LNDhub غير صالح",
"lightning_saved": "تم حفظ تغييراتك بنجاح",
"lightning_settings": "إعدادات البرق",
"lightning_settings_explain": "للاتصال بنود LND الخاص بك، يُرجى تثبيت LNDHub ثم وضع رابطه هنا في الإعدادات. تذكر: فقط المحافظ التي يتم إنشاؤها بعد حفظ التغييرات ستتصل بنود LNDHub التي قمت بإضافتها.",
"lightning_settings_explain": "للاتصال بنود LND الخاص بك، يُرجى تثبيت LNDhub ثم وضع رابطه هنا في الإعدادات. تذكر: فقط المحافظ التي يتم إنشاؤها بعد حفظ التغييرات ستتصل بنود LNDhub التي قمت بإضافتها.",
"network": "الشبكة",
"network_broadcast": "بث العملية",
"network_electrum": "خادم Electrum",
@ -345,7 +345,7 @@
"add_import_wallet": "استيراد محفظة",
"add_lightning": "البرق",
"add_lightning_explain": "لإرسال المعاملات بشكل فوري عبر شبكة البرق",
"add_lndhub": "اتصل ب LNDHub الخاص بك",
"add_lndhub": "اتصل ب LNDhub الخاص بك",
"add_lndhub_error": "عنوان النود المقدَّم غير صالح.",
"add_lndhub_placeholder": "عنوان النود الخاص بك",
"add_placeholder": "محفظتي الأولى",

View File

@ -174,7 +174,7 @@
"electrum_connected_not": "Няма връзка",
"electrum_saved": "Промените бяха запазени успешно. Моля, рестартирайте Блу Уолет за да видите промените.",
"set_electrum_server_as_default": "Задайте {server} като Електрум сървър по подразбиране? ",
"set_lndhub_as_default": "Задайте {url} като LNDHub сървър по подразбиране?",
"set_lndhub_as_default": "Задайте {url} като LNDhub сървър по подразбиране?",
"electrum_status": "Статус",
"electrum_clear_alert_title": "Изчисти историята?",
"electrum_clear_alert_message": "Искате ли да изтриете електрум сървър историята?",

View File

@ -199,7 +199,7 @@
"electrum_offline_mode": "هالت آفلاین",
"use_ssl": "SSL نه به کار بگر",
"set_electrum_server_as_default": "{server} سی سرور پؽش فرز الکترام ساموو بۊوه؟",
"set_lndhub_as_default": "{server} سی سرور پؽش فرز LNDHub ساموو بۊوه؟",
"set_lndhub_as_default": "{server} سی سرور پؽش فرز LNDhub ساموو بۊوه؟",
"electrum_settings_server": "سرور الکترام",
"electrum_settings_explain": "سی استفاڌه زه سامووا پؽش فرز، بؽلین پتی بمهنه.",
"electrum_status": "وزیت",
@ -224,10 +224,10 @@
"last_updated": "ورۊ رسۊوی دیندایی",
"language_isRTL": "ره وندن دووارته BlueWallet سی انجوم آلشت کاریا ری زۉ الن وا انجوم بۊ.",
"license": "موجوز",
"lightning_error_lndhub_uri": "یۊآرآی LNDHub زبال نؽ",
"lightning_error_lndhub_uri": "یۊآرآی LNDhub زبال نؽ",
"lightning_saved": "آلشت کاریا ایسا وه خۊوی زفت وابین.",
"lightning_settings": "سامووا لایتنینگ",
"lightning_settings_explain": "سی منپیز وه گره LND خوت، LNDHub نه بپۊرن ۉ آدرسسه ایچونا منه سامووا بنه. ویرت بۊ که کیف پیلا وورکل وابیڌه دیندا زفت کردن آلشت کاریا وه LNDHub موشخس وابیڌه منپیز ابۊ.",
"lightning_settings_explain": "سی منپیز وه گره LND خوت، LNDhub نه بپۊرن ۉ آدرسسه ایچونا منه سامووا بنه. ویرت بۊ که کیف پیلا وورکل وابیڌه دیندا زفت کردن آلشت کاریا وه LNDhub موشخس وابیڌه منپیز ابۊ.",
"network": "شبکه",
"network_electrum": "سرور الکترام",
"notifications": "وارسۊویا",

View File

@ -194,7 +194,7 @@
"header": "Configuració",
"language": "Idioma",
"last_updated": "Última actualització",
"lightning_error_lndhub_uri": "LNDHub URI no vàlid",
"lightning_error_lndhub_uri": "LNDhub URI no vàlid",
"lightning_settings": "Configuració Lightning",
"network": "Xarxa",
"network_electrum": "Servidor Electrum",

View File

@ -247,7 +247,7 @@
"use_ssl": "Použít protokol SSL",
"electrum_saved": "Vaše změny byly úspěšně uloženy. Změny se projeví až po restartu aplikace BlueWallet.",
"set_electrum_server_as_default": "Nastavit {server} jako výchozí Electrum server?",
"set_lndhub_as_default": "Nastavit {url} jako výchozí LNDHub server?",
"set_lndhub_as_default": "Nastavit {url} jako výchozí LNDhub server?",
"electrum_settings_server": "Electrum server",
"electrum_settings_explain": "Chcete-li použít výchozí nastavení, ponechte pole prázdné.",
"electrum_status": "Stav",
@ -272,7 +272,7 @@
"biometrics_fail": "Pokud {type} není povolen, nebo selže při odemykání, můžete jako alternativu použít přístupový kód vašeho zařízení.",
"general": "Obecné",
"general_adv_mode": "Pokročilý režim",
"general_adv_mode_e": "Pokud je povolen, uvidíte pokročilé možnosti, například různé typy peněženek, možnost určit instanci LNDHub, ke které se chcete připojit, a vlastní entropii během vytváření peněženky.",
"general_adv_mode_e": "Pokud je povolen, uvidíte pokročilé možnosti, například různé typy peněženek, možnost určit instanci LNDhub, ke které se chcete připojit, a vlastní entropii během vytváření peněženky.",
"general_continuity": "Kontinuita",
"general_continuity_e": "Pokud je povolena, budete moci prohlížet vybrané peněženky a transakce pomocí ostatních zařízení připojených k Apple iCloud.",
"groundcontrol_explanation": "GroundControl je bezplatný open source server push oznámení pro bitcoinové peněženky. Můžete si nainstalovat svůj vlastní server GroundControl a vložit sem jeho URL, abyste se nespoléhali na infrastrukturu BlueWallet. Chcete-li použít výchozí server, ponechte pole prázdné.",
@ -281,10 +281,10 @@
"last_updated": "Naposledy aktualizováno",
"language_isRTL": "Aby se projevila změna nastavení jazyka, je nutné restartovat BlueWallet.",
"license": "Licence",
"lightning_error_lndhub_uri": "Neplatná LNDHub URI",
"lightning_error_lndhub_uri": "Neplatná LNDhub URI",
"lightning_saved": "Vaše změny byly úspěšně uloženy.",
"lightning_settings": "Nastavení Lightning",
"lightning_settings_explain": "Chcete-li se připojit k vlastnímu uzlu LND, nainstalujte si LNDHub a zde v nastavení zadejte jeho adresu URL. Upozorňujeme, že k zadanému LNDHubu se připojí pouze peněženky vytvořené po uložení změn.",
"lightning_settings_explain": "Chcete-li se připojit k vlastnímu uzlu LND, nainstalujte si LNDhub a zde v nastavení zadejte jeho adresu URL. Upozorňujeme, že k zadanému LNDHubu se připojí pouze peněženky vytvořené po uložení změn.",
"network": "Síť",
"network_broadcast": "Odeslat transakci",
"network_electrum": "Electrum server",
@ -389,8 +389,8 @@
"add_import_wallet": "Importovat peněženku",
"add_lightning": "Lightning",
"add_lightning_explain": "Pro utrácení s okamžitými transakcemi",
"add_lndhub": "Připojte se k vašemu LNDHub",
"add_lndhub_error": "Zadaná adresa uzlu je neplatný LNDHub uzel.",
"add_lndhub": "Připojte se k vašemu LNDhub",
"add_lndhub_error": "Zadaná adresa uzlu je neplatný LNDhub uzel.",
"add_lndhub_placeholder": "Adresa vašeho uzlu",
"add_placeholder": "moje první peněženka",
"add_title": "Přidat peněženku",

View File

@ -245,7 +245,7 @@
"use_ssl": "SSL verwenden",
"electrum_saved": "Deine Änderungen wurden gespeichert. Zur Aktivierung ist ggf. ein Neustart von BlueWallet erforderlich.",
"set_electrum_server_as_default": "{server} als Standard Electrum-Server setzten?",
"set_lndhub_as_default": "{url} als Standard LNDHub-Server setzten?",
"set_lndhub_as_default": "{url} als Standard LNDhub-Server setzten?",
"electrum_settings_server": "Electrum Server",
"electrum_settings_explain": "Leer lassen, um den Standard zu verwenden.",
"electrum_status": "Status",
@ -270,7 +270,7 @@
"biometrics_fail": "Wenn {type} nicht aktiviert ist oder entsperrt werden kann, alternativ Ihren Gerätepasscode verwenden.",
"general": "Allgemein",
"general_adv_mode": "Erweiterter Modus",
"general_adv_mode_e": "Erlaubt, wenn aktiviert, verschiedene Wallet-Typen anzulegen, dabei eine benutzerdefinierte Entropie zu verwenden und die LNDHub-Instanz der Lightning Wallet frei zu definieren.",
"general_adv_mode_e": "Erlaubt, wenn aktiviert, verschiedene Wallet-Typen anzulegen, dabei eine benutzerdefinierte Entropie zu verwenden und die LNDhub-Instanz der Lightning Wallet frei zu definieren.",
"general_continuity": "Kontinuität",
"general_continuity_e": "Wenn aktiviert werden ausgewählte Wallets und deren Transaktionen auf deinen anderen Apple iCloud Geräten angezeigt.",
"groundcontrol_explanation": "GroundControl ist ein kostenloser Open-Source Push-Benachrichtigungsdienst für Bitcoin-Wallets. Trage hier die URL eines selbst aufgesetzten GroundControl-Servers ein, um von BlueWallet unabhängig zu bleiben. Leer lassen, um die Standardeinstellung zu verwenden.",
@ -279,10 +279,10 @@
"last_updated": "Zuletzt aktualisiert",
"language_isRTL": "BlueWallet zur Aktivierung der Änderung der Schriftrichtung neu starten.",
"license": "Lizenz",
"lightning_error_lndhub_uri": "Keine gültige LndHub URI",
"lightning_error_lndhub_uri": "Keine gültige LNDhub URI",
"lightning_saved": "Deine Änderungen wurden gespeichert.",
"lightning_settings": "Lightning-Einstellungen",
"lightning_settings_explain": "Zur Verbindung mit einem eigenen LND-Knoten LNDHub installieren und dessen URL hier eingeben. Bitte beachte, dass nur Wallets, die nach dem Speichern der Änderungen erstellt werden, mit dem angegebenen LNDHub verbunden werden.",
"lightning_settings_explain": "Zur Verbindung mit einem eigenen LND-Knoten LNDhub installieren und dessen URL hier eingeben. Bitte beachte, dass nur Wallets, die nach dem Speichern der Änderungen erstellt werden, mit dem angegebenen LNDhub verbunden werden.",
"network": "Netzwerk",
"network_broadcast": "Transaktion publizieren",
"network_electrum": "Electrum Server",
@ -379,8 +379,8 @@
"add_import_wallet": "Wallet importieren",
"add_lightning": "Lightning",
"add_lightning_explain": "Für Ausgaben mit sofortigen Transaktionen",
"add_lndhub": "LNDHub Verbindung",
"add_lndhub_error": "Die eingegebene Adresse ist kein gültiger LNDHub Konten.",
"add_lndhub": "LNDhub Verbindung",
"add_lndhub_error": "Die eingegebene Adresse ist kein gültiger LNDhub Konten.",
"add_lndhub_placeholder": "Bitcoin Knoten-Adresse",
"add_placeholder": "Mein Wallet",
"add_title": "Wallet hinzufügen",

View File

@ -196,7 +196,7 @@
"language": "Γλώσσα",
"last_updated": "Τελευταία ενημέρωση",
"license": "Άδεια χρήσης",
"lightning_error_lndhub_uri": "Μη έγκυρο LNDHub URI",
"lightning_error_lndhub_uri": "Μη έγκυρο LNDhub URI",
"lightning_saved": "Η αλλαγές σας αποθηκεύτηκαν με επιτυχία.",
"lightning_settings": "Ρυθμίσεις Lightning",
"network": "Δίκτυο",
@ -255,7 +255,7 @@
"add_entropy": "Εντροπία",
"add_import_wallet": "Εισαγωγή πορτοφολιού",
"add_lightning": "Lightning",
"add_lndhub": "Σύνδεση στο δικό σας LNDHub",
"add_lndhub": "Σύνδεση στο δικό σας LNDhub",
"add_lndhub_placeholder": "Η διεύθυνση του κόμβου σας",
"add_placeholder": "το πρώτο μου πορτοφόλι",
"add_title": "Προσθήκη πορτοφολιού",

View File

@ -219,7 +219,6 @@
"about_sm_twitter": "Follow us on Twitter",
"privacy_temporary_screenshots": "Allow Screenshots",
"privacy_temporary_screenshots_instructions": "Screen capture protection will be turned off for this session, allowing you to take screenshots. Once you close and reopen the app, the protection will be automatically turned back on.",
"advanced_options": "Advanced Options",
"biometrics": "Biometrics",
"biometrics_no_longer_available": "Your device settings have changed and no longer match the selected security settings in the app. Please re-enable biometrics or passcode, then restart the app to apply these changes.",
"biom_10times": "You have attempted to enter your password 10 times. Would you like to reset your storage? This will remove all wallets and decrypt your storage.",
@ -244,7 +243,7 @@
"use_ssl": "Use SSL",
"electrum_saved": "Your changes have been saved successfully. Restarting BlueWallet may be required for the changes to take effect.",
"set_electrum_server_as_default": "Set {server} as the default Electrum server?",
"set_lndhub_as_default": "Set {url} as the default LNDHub server?",
"set_lndhub_as_default": "Set {url} as the default LNDhub server?",
"electrum_settings_server": "Electrum Server",
"electrum_settings_explain": "Leave blank to use the default.",
"electrum_status": "Status",
@ -272,8 +271,6 @@
"encrypt_use_expl": "{type} will be used to confirm your identity before making a transaction, unlocking, exporting, or deleting a wallet. {type} will not be used to unlock encrypted storage.",
"biometrics_fail": "If {type} is not enabled, or fails to unlock, you can use your device passcode as an alternative.",
"general": "General",
"general_adv_mode": "Advanced Mode",
"general_adv_mode_e": "When enabled, you will see advanced options such as different wallet types, the ability to specify the LNDHub instance you wish to connect to, and custom entropy during wallet creation.",
"general_continuity": "Continuity",
"general_continuity_e": "When enabled, you will be able to view selected wallets, and transactions, using your other Apple iCloud connected devices.",
"groundcontrol_explanation": "GroundControl is a free, open-source push notifications server for Bitcoin wallets. You can install your own GroundControl server and put its URL here to not rely on BlueWallets infrastructure. Leave blank to use GroundControls default server.",
@ -282,10 +279,10 @@
"last_updated": "Last Updated",
"language_isRTL": "Restarting BlueWallet is required for the language orientation to take effect.",
"license": "License",
"lightning_error_lndhub_uri": "Invalid LNDHub URI",
"lightning_error_lndhub_uri": "Invalid LNDhub URI",
"lightning_saved": "Your changes have been saved successfully.",
"lightning_settings": "Lightning Settings",
"lightning_settings_explain": "To connect to your own LND node, please install LNDHub and put its URL here in settings. Please note that only wallets created after saving changes will connect to the specified LNDHub.",
"lightning_settings_explain": "To connect to your own LND node, please install LNDhub and put its URL here in settings. Please note that only wallets created after saving changes will connect to the specified LNDhub.",
"network": "Network",
"network_broadcast": "Broadcast Transaction",
"network_electrum": "Electrum Server",
@ -389,8 +386,8 @@
"add_import_wallet": "Import wallet",
"add_lightning": "Lightning",
"add_lightning_explain": "For spending with instant transactions",
"add_lndhub": "Connect to your LNDHub",
"add_lndhub_error": "The provided node address is an invalid LNDHub node.",
"add_lndhub": "Connect to your LNDhub",
"add_lndhub_error": "The provided node address is an invalid LNDhub node.",
"add_lndhub_placeholder": "Your Node Address",
"add_placeholder": "my first wallet",
"add_title": "Add Wallet",
@ -424,7 +421,6 @@
"wallets": "Wallets",
"details_type": "Type",
"details_use_with_hardware_wallet": "Use with Hardware Wallet",
"details_wallet_updated": "Wallet updated",
"details_yes_delete": "Yes, delete",
"enter_bip38_password": "Enter password to decrypt",
"export_title": "Wallet Export",
@ -440,6 +436,7 @@
"import_success_watchonly": "Your wallet has been successfully imported. WARNING: This is a watch-only wallet, you can NOT spend from it.",
"import_search_accounts": "Search accounts",
"import_title": "Import",
"learn_more": "Learn more",
"import_discovery_title": "Discovery",
"import_discovery_subtitle": "Choose a discovered wallet",
"import_discovery_derivation": "Use custom derivation path",
@ -479,7 +476,8 @@
"add_ln_wallet_first": "You must first add a Lightning wallet.",
"identity_pubkey": "Identity Pubkey",
"xpub_title": "Wallet XPUB",
"manage_wallets_search_placeholder": "Search wallets, memos"
"manage_wallets_search_placeholder": "Search wallets, memos",
"more_info": "More Info"
},
"total_balance_view": {
"view_in_bitcoin": "View in Bitcoin",
@ -489,7 +487,7 @@
"explanation": "View the total balance of all your wallets in the overview screen."
},
"multisig": {
"multisig_vault": "Vault",
"multisig_vault": "Multisig Vault",
"default_label": "Multisig Vault",
"multisig_vault_explain": "Best security for large amounts",
"provide_signature": "Provide signature",

View File

@ -210,7 +210,7 @@
"use_ssl": "Utiliza SSL",
"electrum_saved": "Los cambios se han guardado. Puede que se requiera reiniciar la aplicación para que tomen efecto.",
"set_electrum_server_as_default": "¿Establecer {server} como servidor Electrum por defecto?",
"set_lndhub_as_default": "¿Establecer {url} como servidor LNDHub por defecto?",
"set_lndhub_as_default": "¿Establecer {url} como servidor LNDhub por defecto?",
"electrum_settings_server": "Servidor Electrum",
"electrum_settings_explain": "Déjalo en blanco para usar el predeterminado.",
"electrum_status": "Estado",
@ -233,7 +233,7 @@
"encrypt_use_expl": "{type} se utilizará para confirmar tu identidad antes de realizar una transacción, desbloquear, exportar o eliminar una billetera. {type} no se utilizará para desbloquear el almacenamiento encriptado.",
"general": "General",
"general_adv_mode": "Modo avanzado",
"general_adv_mode_e": "Al activarlo podrás ver opciones avanzadas, como varios tipos de carteras, la posibilidad de especificar el LNDHub al que quieres conectar y entropía personalizada al crear una cartera.",
"general_adv_mode_e": "Al activarlo podrás ver opciones avanzadas, como varios tipos de carteras, la posibilidad de especificar el LNDhub al que quieres conectar y entropía personalizada al crear una cartera.",
"general_continuity": "Continuidad",
"general_continuity_e": "Al activarlo, podrá ver las transacciones y carteras seleccionadas usando cualquiera de sus dispositivos Apple conectados a iCloud.",
"groundcontrol_explanation": "GroundControl es un servidor gratuito y de código abierto de notificaciones push para carteras Bitcoin. Puedes instalar tu propio servidor de GroundControl y poner su URL aquí para no depender del de BlueWallet. Déjalo en blanco para usar el predeterminado.",
@ -241,7 +241,7 @@
"language": "Idioma",
"last_updated": "Última actualización",
"language_isRTL": "Al seleccionar otro idioma, será necesario reiniciar BlueWallet para mostrar los cambios.",
"lightning_error_lndhub_uri": "LndHub URI no válida",
"lightning_error_lndhub_uri": "LNDhub URI no válida",
"lightning_saved": "Tus cambios se han guardado correctamente",
"lightning_settings": "Configuración de Lightning",
"network": "Red",
@ -334,7 +334,7 @@
"add_lightning": "Lightning",
"add_lightning_explain": "Para pagos con transferencias instantáneas",
"add_lndhub": "Conecta a tu LDNHub",
"add_lndhub_error": "La dirección proporcionada no es válida para un nodo LNDHub.",
"add_lndhub_error": "La dirección proporcionada no es válida para un nodo LNDhub.",
"add_lndhub_placeholder": "La dirección de tu nodo",
"add_placeholder": "Mi primera cartera",
"add_title": "Añadir cartera",

View File

@ -219,7 +219,6 @@
"about_sm_twitter": "Siguenos en Twitter",
"privacy_temporary_screenshots": "Permitir capturas de pantalla",
"privacy_temporary_screenshots_instructions": "La protección contra capturas de pantalla se desactivará para esta sesión, permitiéndote hacer capturas de pantalla. Cuando cierres y vuelvas a abrir la aplicación, la protección volverá a activarse automáticamente.",
"advanced_options": "Opciones Avanzadas",
"biometrics": "Biometría",
"biometrics_no_longer_available": "La configuración de tu dispositivo cambió y ya no coincide con la configuración de seguridad seleccionada en la aplicación. Vuelve a habilitar los datos biométricos o el código de acceso, luego reinicia la aplicación para aplicar estos cambios.",
"biom_10times": "Has intentado ingresar tu contraseña 10 veces. ¿Te gustaría restablecer tu almacenamiento? Esto eliminará todas las billeteras y descifrará tu almacenamiento.",
@ -244,7 +243,7 @@
"use_ssl": "Utiliza SSL",
"electrum_saved": "Tus cambios se han guardado correctamente. Es necesario reiniciar para que los cambios surtan efecto.",
"set_electrum_server_as_default": "Establecer {server} como el servidor Electrum predeterminado?",
"set_lndhub_as_default": "¿Establecer {url} como servidor LNDHub predeterminado?",
"set_lndhub_as_default": "¿Establecer {url} como servidor LNDhub predeterminado?",
"electrum_settings_server": "Servidor Electrum",
"electrum_settings_explain": "Déjalo en blanco para usar el predeterminado.",
"electrum_status": "Estado",
@ -272,8 +271,6 @@
"encrypt_use_expl": "{type} se utilizará para confirmar tu identidad antes de realizar una transacción, desbloquear, exportar o eliminar una billetera. {type} no se utilizará para desbloquear el almacenamiento encriptado.",
"biometrics_fail": "Si {type} no está activado o no se desbloquea, puedes utilizar el código de acceso de tu dispositivo como alternativa.",
"general": "General",
"general_adv_mode": "Modo Avanzado",
"general_adv_mode_e": "Cuando esté habilitado, verás opciones avanzadas como diferentes tipos de billetera, la capacidad de especificar la instancia de LNDHub a la que deseas conectarte y la entropía personalizada durante la creación de la billetera.",
"general_continuity": "Continuidad",
"general_continuity_e": "Cuando esté habilitado, podrás ver carteras seleccionadas y transacciones utilizando tus otros dispositivos conectados a Apple iCloud.",
"groundcontrol_explanation": "GroundControl es un servidor de notificaciones push de código abierto gratuito para billeteras Bitcoin. Puedes instalar tu propio servidor GroundControl y poner tu URL aquí para no depender de la infraestructura de BlueWallet. Déjalo en blanco para usar el predeterminado.",
@ -282,10 +279,10 @@
"last_updated": "Última actualización",
"language_isRTL": "Es necesario reiniciar BlueWallet para que la orientación del idioma surta efecto.",
"license": "Licencia",
"lightning_error_lndhub_uri": "URI de LNDHub inválido",
"lightning_error_lndhub_uri": "URI de LNDhub no válido",
"lightning_saved": "Tus cambios han sido guardados correctamente.",
"lightning_settings": "Configuración de Lightning",
"lightning_settings_explain": "Para conectarte a tu propio nodo LND, instala LNDHub y coloca tu URL aquí en la configuración. Ten en cuenta que solo las billeteras creadas después de guardar los cambios se conectarán al LNDHub especificado.",
"lightning_settings_explain": "Para conectarte a tu propio nodo LND, instala LNDhub y coloca su URL aquí en la configuración. Ten en cuenta que solo las billeteras creadas después de guardar los cambios se conectarán al LNDhub especificado.",
"network": "Red",
"network_broadcast": "Publicar transacción",
"network_electrum": "Servidor Electrum",
@ -389,8 +386,8 @@
"add_import_wallet": "Importar billetera",
"add_lightning": "Lightning",
"add_lightning_explain": "Para gastar con transacciones instantáneas",
"add_lndhub": "Conectar a tu LNDHub",
"add_lndhub_error": "La dirección de nodo proporcionada es un nodo LNDHub inválido.",
"add_lndhub": "Conéctate a tu LNDhub",
"add_lndhub_error": "La dirección de nodo proporcionada es un nodo LNDhub no válido.",
"add_lndhub_placeholder": "Tu Dirección de Nodo",
"add_placeholder": "mi primera billetera",
"add_title": "Agregar Billetera",
@ -440,6 +437,7 @@
"import_success_watchonly": "Tu billetera se ha importado correctamente. ADVERTENCIA: Esta es una billetera de \"solo ver\", NO puedes gastar desde él.",
"import_search_accounts": "Buscar cuentas",
"import_title": "Importar",
"learn_more": "Saber más",
"import_discovery_title": "Descubrimiento",
"import_discovery_subtitle": "Elige una billetera descubierta",
"import_discovery_derivation": "Utilizar una ruta de derivación personalizada",
@ -479,7 +477,8 @@
"add_ln_wallet_first": "Primero debes agregar una billetera Lightning.",
"identity_pubkey": "Identidad Pubkey",
"xpub_title": "XPUB de la billetera",
"manage_wallets_search_placeholder": "Buscar billeteras, notas"
"manage_wallets_search_placeholder": "Buscar billeteras, notas",
"more_info": "Más información"
},
"total_balance_view": {
"view_in_bitcoin": "Ver en Bitcoin",
@ -489,7 +488,7 @@
"explanation": "Ve el saldo total de todas tus billeteras en la pantalla de descripción general."
},
"multisig": {
"multisig_vault": "Bóveda",
"multisig_vault": "Bóveda Multifirma",
"default_label": "Bóveda Multifirma",
"multisig_vault_explain": "La mejor seguridad para grandes cantidades",
"provide_signature": "Proporcionar firma",

View File

@ -222,7 +222,7 @@
"use_ssl": "از SSL استفاده کن",
"electrum_saved": "تغییرات شما با موفقیت ذخیره شدند. ممکن است برای اعمال تغییرات به راه‌اندازی مجدد برنامه نیاز داشته باشید.",
"set_electrum_server_as_default": "آیا {server} به‌عنوان سرور پیش‌فرض الکترام تعیین شود؟",
"set_lndhub_as_default": "آیا {url} به‌عنوان سرور پیش‌فرض LNDHub تعیین شود؟",
"set_lndhub_as_default": "آیا {url} به‌عنوان سرور پیش‌فرض LNDhub تعیین شود؟",
"electrum_settings_server": "سرور الکترام",
"electrum_settings_explain": "برای استفاده از تنظیمات پیش‌فرض خالی بگذارید.",
"electrum_status": "وضعیت",
@ -245,7 +245,7 @@
"encrypt_use_expl": "از {type} برای تأیید هویت شما قبل از انجام تراکنش، بازکردن قفل، صادرکردن، یا حذف کیف پول استفاده خواهد شد. از {type} برای بازکردن فضای ذخیره‌سازی رمزگذاری‌شده استفاده نخواهد شد.",
"general": "عمومی",
"general_adv_mode": "حالت پیشرفته",
"general_adv_mode_e": "درصورت فعال‌بودن، گزینه‌های پیشرفته‌ای مانند انواع مختلف کیف پول، امکان تعیین سرور LNDHub جهت اتصال، و آنتروپی سفارشی را در هنگام ایجاد کیف پول مشاهده خواهید کرد.",
"general_adv_mode_e": "درصورت فعال‌بودن، گزینه‌های پیشرفته‌ای مانند انواع مختلف کیف پول، امکان تعیین سرور LNDhub جهت اتصال، و آنتروپی سفارشی را در هنگام ایجاد کیف پول مشاهده خواهید کرد.",
"general_continuity": "پیوستگی",
"general_continuity_e": "درصورت فعال‌بودن، می‌توانید کیف پول‌های انتخاب‌شده و تراکنش‌ها را با استفاده از سایر دستگاه‌های متصل به Apple iCloud خود مشاهده کنید.",
"groundcontrol_explanation": "سرویس GroundControl یک سرور اعلانات متن‌باز و رایگان برای کیف پول‌های بیت‌کوین است. شما می‌توانید سرور GroundControl خود را نصب کرده و آدرس آن را اینجا قرار دهید تا به زیرساخت‌های BlueWallet متکی نباشید. برای استفاده از تنظیمات پیش‌فرض خالی بگذارید.",
@ -254,10 +254,10 @@
"last_updated": "آخرین به‌روزرسانی",
"language_isRTL": "راه‌اندازی مجدد BlueWallet جهت اعمال تغییرات چینش زبان ضروری است.",
"license": "پروانه",
"lightning_error_lndhub_uri": "یوآرآی LNDHub غیرمعتبر",
"lightning_error_lndhub_uri": "یوآرآی LNDhub غیرمعتبر",
"lightning_saved": "تغییرات شما با موفقیت ذخیره شدند.",
"lightning_settings": "تنظیمات لایتنینگ",
"lightning_settings_explain": "برای اتصال به گره LND خود، لطفاً LNDHub را نصب کرده و آدرس آن را اینجا در تنظیمات قرار دهید. توجه داشته باشید که کیف پول‌های ایجادشده بعد از ذخیرهٔ تغییرات به LNDHub مشخص‌شده متصل خواهند شد.",
"lightning_settings_explain": "برای اتصال به گره LND خود، لطفاً LNDhub را نصب کرده و آدرس آن را اینجا در تنظیمات قرار دهید. توجه داشته باشید که کیف پول‌های ایجادشده بعد از ذخیرهٔ تغییرات به LNDhub مشخص‌شده متصل خواهند شد.",
"network": "شبکه",
"network_broadcast": "انتشار تراکنش",
"network_electrum": "سرور الکترام",
@ -348,8 +348,8 @@
"add_import_wallet": "واردکردن کیف پول",
"add_lightning": "لایتنینگ",
"add_lightning_explain": "برای خرج‌کردن با تراکنش‌های آنی",
"add_lndhub": "به LNDHub خود متصل شوید",
"add_lndhub_error": "آدرس گره ارائه‌شده گره LNDHub معتبری نیست.",
"add_lndhub": "به LNDhub خود متصل شوید",
"add_lndhub_error": "آدرس گره ارائه‌شده گره LNDhub معتبری نیست.",
"add_lndhub_placeholder": "آدرس گره شما",
"add_placeholder": "کیف پول اول من",
"add_title": "افزودن کیف پول",

View File

@ -237,7 +237,7 @@
"use_ssl": "Käytä SSL",
"electrum_saved": "Muutoksesi on tallennettu onnistuneesti. Uudelleenkäynnistys voi olla tarpeen, jotta muutokset tulevat voimaan.",
"set_electrum_server_as_default": "Asetetaanko {server} oletus Electrum-palvelimeksi?",
"set_lndhub_as_default": "Asetetaanko {url} oletus LNDHub-palvelimeksi?",
"set_lndhub_as_default": "Asetetaanko {url} oletus LNDhub-palvelimeksi?",
"electrum_settings_server": "Electrum-palvelin",
"electrum_settings_explain": "Jos haluat käyttää oletusta, jätä tämä tyhjäksi.",
"electrum_status": "Tila",
@ -260,7 +260,7 @@
"encrypt_use_expl": "Ennen tapahtumia, avaamista vientiä tai lompakon poistoa identiteettis varmistetaan {type}:lla. {type} ei kuitenkaan voi käyttää salatun tallennustilan avaamiseen.",
"general": "Yleinen",
"general_adv_mode": "Lisäasetukset",
"general_adv_mode_e": "Kun tämä asetus on käytössä, näet lisäasetukset, kuten erilaiset lompakkotyypit, kyvyn määrittää LNDHub-instanssi, johon haluat muodostaa yhteyden ja mukautetun entropian lompakon luomisen aikana.",
"general_adv_mode_e": "Kun tämä asetus on käytössä, näet lisäasetukset, kuten erilaiset lompakkotyypit, kyvyn määrittää LNDhub-instanssi, johon haluat muodostaa yhteyden ja mukautetun entropian lompakon luomisen aikana.",
"general_continuity": "Jatkuvuus",
"general_continuity_e": "Kun tämä asetus on käytössä, voit tarkastella valittuja lompakoita ja siirtotapahtumia muilla Apple iCloud -laitteilla.",
"groundcontrol_explanation": "GroundControl on ilmainen avoimen lähdekoodin push-ilmoituspalvelin bitcoin-lompakoille. Voit asentaa oman GroundControl-palvelimen ja laittaa sen URL-osoitteen tähän, jotta et luota BlueWallet-infrastruktuuriin. Jätä tyhjäksi käyttääksesi oletusasetusta",
@ -269,10 +269,10 @@
"last_updated": "Päivitetty viimeksi",
"language_isRTL": "BlueWallet on käynnistettävä uudelleen, jotta kielisuuntaus tulee voimaan.",
"license": "Lisenssi",
"lightning_error_lndhub_uri": "Virheellinen LNDHub URI",
"lightning_error_lndhub_uri": "Virheellinen LNDhub URI",
"lightning_saved": "Muutoksesi on tallennettu onnistuneesti",
"lightning_settings": "Salama-asetukset",
"lightning_settings_explain": "Jos haluat muodostaa yhteyden omaan LND-solmuun, asenna LNDHub ja laita sen URL-osoite tähän asetuksiin. Huomaa, että vain muutosten tallentamisen jälkeen luodut lompakot muodostavat yhteyden määritettyyn LNDHubiin.",
"lightning_settings_explain": "Jos haluat muodostaa yhteyden omaan LND-solmuun, asenna LNDhub ja laita sen URL-osoite tähän asetuksiin. Huomaa, että vain muutosten tallentamisen jälkeen luodut lompakot muodostavat yhteyden määritettyyn LNDHubiin.",
"network": "Verkko",
"network_broadcast": "Lähetä siirtotapahtuma",
"network_electrum": "Electrum-palvelin",
@ -368,8 +368,8 @@
"add_import_wallet": "Tuo lompakko",
"add_lightning": "Salama",
"add_lightning_explain": "Käytetään välittömiin siirtotapahtumiin",
"add_lndhub": "Yhdistä LNDHub:iisi",
"add_lndhub_error": "Annettu solmun osoite ei ole kelvollinen LNDHub solmu",
"add_lndhub": "Yhdistä LNDhub:iisi",
"add_lndhub_error": "Annettu solmun osoite ei ole kelvollinen LNDhub solmu",
"add_lndhub_placeholder": "solmusi osoite",
"add_placeholder": "minun lompakkoni",
"add_title": "lisää lompakko",

View File

@ -222,7 +222,7 @@
"use_ssl": "Utiliser SSL",
"electrum_saved": "Les changements ont bien été enregistrés. Un redémarrage sera peut-être nécessaires pour qu'ils prennent effet.",
"set_electrum_server_as_default": "Mettre {server} come serveur electrum par défaut ?",
"set_lndhub_as_default": "Mettre {url} comme serveur LNDHub par défaut?",
"set_lndhub_as_default": "Mettre {url} comme serveur LNDhub par défaut?",
"electrum_settings_server": "Serveur Electrum",
"electrum_settings_explain": "Laisser blanc pour utiliser l'option par défaut",
"electrum_status": "Statut",
@ -245,7 +245,7 @@
"encrypt_use_expl": "{type} sera utilisé pour confirmer votre identité avant d'effectuer une transaction, de déverrouiller, d'exporter ou de supprimer un portefeuille. {type} ne sera pas utilisé pour déverrouiller le stockage chiffré.",
"general": "Général",
"general_adv_mode": "Mode avancé",
"general_adv_mode_e": "Si activé, vous aurez accès aux options avancées telles que la sélection parmi différents types de portefeuilles, la possibilité de spécifier une instance LNDHub de votre choix, et la création manuelle d'entropie lors de la création de portefeuille.",
"general_adv_mode_e": "Si activé, vous aurez accès aux options avancées telles que la sélection parmi différents types de portefeuilles, la possibilité de spécifier une instance LNDhub de votre choix, et la création manuelle d'entropie lors de la création de portefeuille.",
"general_continuity": "Continuité",
"general_continuity_e": "Si activé, vous pourrez visualiser les portefeuilles sélectionnés ainsi que leurs transactions depuis vos autres appareils Apple iCloud connectés.",
"groundcontrol_explanation": "GroundControl est un serveur de notifications push pour les portefeuilles Bitcoin gratuit et open source. Vous pouvez installer votre propre serveur GroundControl et insérer ici son URL pour ne pas reposer sur l'infrastructure de BlueWallet. Laissez vide pour conserver l'option par défaut.",
@ -253,10 +253,10 @@
"language": "Langue",
"last_updated": "Dernière mise à jour",
"language_isRTL": "Il est nécessaire de redémarrer BlueWallet pour que le changement de langue prenne effet.",
"lightning_error_lndhub_uri": "LNDHub URI invalide",
"lightning_error_lndhub_uri": "LNDhub URI invalide",
"lightning_saved": "Les changements ont bien été enregistrés",
"lightning_settings": "Paramètres Lightning",
"lightning_settings_explain": "Pour connecter votre propre noeud LND, veuillez installer LNDHub et insérez l'URL ici dans les paramètres. Veillez noter que seul les porte-feuilles crées après avoir sauvegardé les changements se connecteront au LNDHub spécifié. ",
"lightning_settings_explain": "Pour connecter votre propre noeud LND, veuillez installer LNDhub et insérez l'URL ici dans les paramètres. Veillez noter que seul les porte-feuilles crées après avoir sauvegardé les changements se connecteront au LNDhub spécifié. ",
"network": "Réseau",
"network_broadcast": "Diffuser une transaction",
"network_electrum": "Serveur Electrum",
@ -349,8 +349,8 @@
"add_import_wallet": "Importer un portefeuille",
"add_lightning": "Lightning",
"add_lightning_explain": "Pour payer avec des transactions instantanées",
"add_lndhub": "Connexion à votre LNDHub",
"add_lndhub_error": "L'adresse de nœud fournie est un nœud LNDHub non valide.",
"add_lndhub": "Connexion à votre LNDhub",
"add_lndhub_error": "L'adresse de nœud fournie est un nœud LNDhub non valide.",
"add_lndhub_placeholder": "l'adresse de votre noeud",
"add_placeholder": "mon premier portefeuille",
"add_title": "ajouter un portefeuille",

View File

@ -94,7 +94,7 @@
"ok": "אוקיי, רשמתי את זה",
"ok_lnd": "אוקיי, שמרתי את זה.",
"text": "אנא קחו רגע כדי לכתוב על דף נייר את מילות הגיבוי האלו. זה הגיבוי שלכם ואיתו תוכלו לשחזר את הארנק.",
"text_lnd": "אנא קחו רגע כדי לשמור את אימות ה- LNDHub. זה הגיבוי איתו תוכלו לשחזר את הארנק על מכשיר אחר.",
"text_lnd": "אנא קחו רגע כדי לשמור את אימות ה- LNDhub. זה הגיבוי איתו תוכלו לשחזר את הארנק על מכשיר אחר.",
"title": "ארנקכם נוצר..."
},
"receive": {
@ -243,7 +243,7 @@
"use_ssl": "הפעלת SSL",
"electrum_saved": "השינויים נשמרו בהצלחה. ייתכן ותדרש הפעלה מחדש כדי שהשינויים ייכנסו לתוקף.",
"set_electrum_server_as_default": "הגדרת {server} כשרת אלקטרום ברירת מחדל?",
"set_lndhub_as_default": "הגדרת {url} כשרת LNDHub ברירת מחדל?",
"set_lndhub_as_default": "הגדרת {url} כשרת LNDhub ברירת מחדל?",
"electrum_settings_server": "שרת אלקטרום",
"electrum_settings_explain": "השאירו ריק כדי להשתמש בברירת מחדל",
"electrum_status": "מצב",
@ -268,7 +268,7 @@
"biometrics_fail": "אם {type} לא מאופשר, או נכשל בפתיחה, תוכלו להשתמש בסיסמת המכשיר שלכם בתור חלופה.",
"general": "כללי",
"general_adv_mode": "מצב מתקדם",
"general_adv_mode_e": "כאשר מופעל, אפשרויות מתקדמות יוצגו כגון סוגי ארנק שונים, אפשרות להתחבר לצומת LNDHub לפי רצונך ואנטרופיה מותאמת בתהליך יצירת ארנק.",
"general_adv_mode_e": "כאשר מופעל, אפשרויות מתקדמות יוצגו כגון סוגי ארנק שונים, אפשרות להתחבר לצומת LNDhub לפי רצונך ואנטרופיה מותאמת בתהליך יצירת ארנק.",
"general_continuity": "המשכיות",
"general_continuity_e": "כאשר מופעל, תוכלו לצפות בארנקים ופעולות נבחרים, באמצעות מכשירי Apple iCloud מחוברים אחרים.",
"groundcontrol_explanation": "שרת GroundControl הינו שרת התראות חופשי בקוד פתוח בשביל ארנקי ביטקוין. באפשרותך להתקין שרת GroundControl אישי ולהכניס את ה- URL שלו כאן, כדי לא להסתמך על התשתית של BlueWallet. השאירו ריק כדי להשתמש בברירת המחדל",
@ -277,10 +277,10 @@
"last_updated": "עודכן לאחרונה",
"language_isRTL": "הפעלה מחדש של BlueWallet נדרשת לשינוי כיוון שפה.",
"license": "רישיון",
"lightning_error_lndhub_uri": " LNDHub URI לא תקני",
"lightning_error_lndhub_uri": " LNDhub URI לא תקני",
"lightning_saved": "השינויים נשמרו בהצלחה",
"lightning_settings": "הגדרות ברק",
"lightning_settings_explain": "כדי להתחבר לצומת LND אישי, אנא התקינו LNDHub והכניסו את כתובת ה- URL שלו כאן בהגדרות. שימו לב שרק ארנקים שנוצרו לאחר שמירת השינויים יתחברו לשרת LNDHub הספציפי.",
"lightning_settings_explain": "כדי להתחבר לצומת LND אישי, אנא התקינו LNDhub והכניסו את כתובת ה- URL שלו כאן בהגדרות. שימו לב שרק ארנקים שנוצרו לאחר שמירת השינויים יתחברו לשרת LNDhub הספציפי.",
"network": "רשת",
"network_broadcast": "שידור פעולה",
"network_electrum": "שרת אלקטרום",
@ -377,8 +377,8 @@
"add_import_wallet": "יבוא ארנק",
"add_lightning": "ברק",
"add_lightning_explain": "לבזבוז עם העברות מידיות",
"add_lndhub": "התחברו ל- LNDHub אישי",
"add_lndhub_error": "כתובת הצומת שסופקה אינה צומת LNDHub תקין.",
"add_lndhub": "התחברו ל- LNDhub אישי",
"add_lndhub_error": "כתובת הצומת שסופקה אינה צומת LNDhub תקין.",
"add_lndhub_placeholder": "כתובת הצומת שלך",
"add_placeholder": "הארנק הראשון שלי",
"add_title": "הוספת ארנק",

View File

@ -84,7 +84,7 @@
"ok": "Rendben, leírtam!",
"ok_lnd": "OK, elmentettem.",
"text": "Kérlek írd le az alábbi biztonsági szavakat egy papírlapra. \nEz egy biztonsági mentés, amellyel helyreállíthatod a tárcádat.",
"text_lnd": "Készíts biztonsági másolatot erről az LNDHub hitelesítésről. Ezzel a biztonsági másolattal visszaállíthatod a tárcát más eszközön.",
"text_lnd": "Készíts biztonsági másolatot erről az LNDhub hitelesítésről. Ezzel a biztonsági másolattal visszaállíthatod a tárcát más eszközön.",
"title": "A tárcád elkészült..."
},
"receive": {
@ -216,7 +216,7 @@
"use_ssl": "SSL Használata",
"electrum_saved": "A változtatás sikeresen elmentve. Az új beállítások aktiválásához űjraindításra lehet szükség.",
"set_electrum_server_as_default": "{server} bállítása alapértelmezett Electrum szerverként?",
"set_lndhub_as_default": "{url} bállítása alapértelmezett LNDHub szerverként?",
"set_lndhub_as_default": "{url} bállítása alapértelmezett LNDhub szerverként?",
"electrum_settings_server": "Electrum Szerver",
"electrum_settings_explain": "Hagydja üresen ha az alapértelmezettet szerené használni.",
"electrum_status": "Állapot",
@ -239,7 +239,7 @@
"encrypt_use_expl": "Igazolja személyazonosságát a {type} a tranzakció végrehajtása, a pénztárca feloldása, exportálása vagy törlése előtt. A {type} nem használható a titkosított tárolás feloldására.",
"general": "Általános",
"general_adv_mode": "Halandó mód bekapcsolása",
"general_adv_mode_e": "Ha engedélyezve van, további opciók is elérhetőek, mint különböző tárca típusok, Lightning LNDHub beállítások és entrópia beállítások tárca készítésénél. ",
"general_adv_mode_e": "Ha engedélyezve van, további opciók is elérhetőek, mint különböző tárca típusok, Lightning LNDhub beállítások és entrópia beállítások tárca készítésénél. ",
"general_continuity": "Folytonosság",
"general_continuity_e": "Ha engedélyezve van, láthatod a kiválasztott tárcákat és tranzakciókat más, csatlakoztatott Apple iCloud eszközökön.",
"groundcontrol_explanation": "A GroundControl egy ingyenes, nyílt forráskodú, push üzenetküldő szerver Bitcoin tárcákhoz. Telepítheted a saját GroundControl szerveredet webcímed megadásával, ami függetlet lesz a BlueWallet infrastuktúrától. Hagyd üresen alapértelmezésben.",
@ -247,7 +247,7 @@
"language": "Nyelv",
"last_updated": "Utoljára Frissítve",
"language_isRTL": "Az új nyelv használatához újra kell indítanod a BlueWallet alkalmazást.",
"lightning_error_lndhub_uri": "Nem megfelelő LNDHub URI",
"lightning_error_lndhub_uri": "Nem megfelelő LNDhub URI",
"lightning_saved": "A változtatások sikeresen elmentve",
"lightning_settings": "Lightning Beállítások",
"network": "Hálózat",
@ -341,8 +341,8 @@
"add_import_wallet": "Tárca importálása",
"add_lightning": "Lightning",
"add_lightning_explain": "Költés azonnali tranzakcióval",
"add_lndhub": "Kapcsolódj az LNDHub-hoz",
"add_lndhub_error": "A megadott LNDHub node cím nem megfelelő.",
"add_lndhub": "Kapcsolódj az LNDhub-hoz",
"add_lndhub_error": "A megadott LNDhub node cím nem megfelelő.",
"add_lndhub_placeholder": "a te node címed",
"add_placeholder": "az első tárcám",
"add_title": "új tárca",

View File

@ -85,7 +85,7 @@
"ask": "Sudahkah Anda menyimpan frase cadangan dompet Anda? Frase cadangan ini diperlukan untuk mengakses dana Anda jika Anda kehilangan perangkat ini. Tanpa frase cadangan, dana Anda akan hilang secara permanen.",
"ok_lnd": "Oke, saya sudah menyimpannya.",
"text": "Silakan tulis frasa mnemonik ini di atas kertas.\nIni adalah cadangan Anda dan Anda bisa menggunakannya untuk memulihkan dompet Anda.",
"text_lnd": "Harap luangkan waktu sejenak untuk menyimpan otentikasi LNDHub ini. Ini cadangan Anda yang dapat Anda gunakan untuk memulihkan dompet di perangkat lain.",
"text_lnd": "Harap luangkan waktu sejenak untuk menyimpan otentikasi LNDhub ini. Ini cadangan Anda yang dapat Anda gunakan untuk memulihkan dompet di perangkat lain.",
"title": "Dompet Anda telah dibuat ..."
},
"receive": {
@ -234,7 +234,7 @@
"header": "setting",
"language": "Bahasa",
"last_updated": "Terakhir Diperbaharui",
"lightning_error_lndhub_uri": "LNDHub URI tidak valid",
"lightning_error_lndhub_uri": "LNDhub URI tidak valid",
"lightning_saved": "Perubahan Anda telah berhasil disimpan.",
"lightning_settings": "Pengaturan Lightning",
"network": "Jaringan",
@ -295,7 +295,7 @@
"add_create": "Buat",
"add_entropy": "Entropi",
"add_import_wallet": "Impor dompet",
"add_lndhub": "Hubungan ke LNDHub Anda",
"add_lndhub": "Hubungan ke LNDhub Anda",
"add_placeholder": "dompet pertama saya",
"add_title": "tambah dompet",
"add_wallet_name": "nama dompet",

View File

@ -219,7 +219,7 @@
"use_ssl": "Usa SSL",
"electrum_saved": "Le tue modifiche sono state salvate con successo. Può essere necessario riavviare BlueWallet affinché le modifiche abbiano effetto.",
"set_electrum_server_as_default": "Impostare {server} come server Electrum predefinito?",
"set_lndhub_as_default": "Impostare {url} come server LNDHub predefinito?",
"set_lndhub_as_default": "Impostare {url} come server LNDhub predefinito?",
"electrum_settings_server": "Server Electrum",
"electrum_settings_explain": "Lascia vuoto per usare il valore predefinito.",
"electrum_status": "Stato",
@ -242,7 +242,7 @@
"encrypt_use_expl": "{type} verrà usato per confermare la tua identità prima di effettuare una transazione, sbloccare, esportare, o eliminare un wallet. {type} non sarà usato per sbloccare archivi cifrati.",
"general": "Generali",
"general_adv_mode": "Enable advanced mode",
"general_adv_mode_e": "Una volta abilitato, vedrai opzioni avanzate come diversi tipi di portafoglio, la possibilità di specificare l'istanza di LNDHub a cui vuoi connetterti, e l'entropia personalizzata durante la creazione del portafoglio.",
"general_adv_mode_e": "Una volta abilitato, vedrai opzioni avanzate come diversi tipi di portafoglio, la possibilità di specificare l'istanza di LNDhub a cui vuoi connetterti, e l'entropia personalizzata durante la creazione del portafoglio.",
"general_continuity": "Continuity",
"general_continuity_e": "Una volta abilitato, sarai in grado di visualizzare i portafogli selezionati e le transazioni, utilizzando i tuoi altri dispositivi collegati ad Apple iCloud.",
"groundcontrol_explanation": "GroundControl è un server di notifiche push gratuito e open-source per i portafogli Bitcoin. Puoi installare il tuo server GroundControl e mettere il suo URL qui per non contare sull'infrastruttura di BlueWallet. Lascia il campo vuoto per usare il server predefinito di GroundControl.",
@ -250,10 +250,10 @@
"language": "Lingua",
"last_updated": "Ultimo aggiornamento",
"language_isRTL": "Il riavvio di BlueWallet è necessario affinché l'orientamento della lingua abbia effetto.",
"lightning_error_lndhub_uri": "LNDHub URI non valido",
"lightning_error_lndhub_uri": "LNDhub URI non valido",
"lightning_saved": "I cambiamenti sono stati registrati con successo.",
"lightning_settings": "Impostazioni Lightning",
"lightning_settings_explain": "Per connetterti al tuo nodo LND, installa LNDHub e inserisci l'URL qui nelle impostazioni. Tieni presente che solo i portafogli che sono stati creati dopo aver salvato le modifiche saranno connessi all'LNDHub specificato.",
"lightning_settings_explain": "Per connetterti al tuo nodo LND, installa LNDhub e inserisci l'URL qui nelle impostazioni. Tieni presente che solo i portafogli che sono stati creati dopo aver salvato le modifiche saranno connessi all'LNDhub specificato.",
"network": "Rete",
"network_broadcast": "Trasmetti transazione",
"network_electrum": "Server Electrum",
@ -343,8 +343,8 @@
"add_import_wallet": "Importa Portafoglio",
"add_lightning": "Lightning",
"add_lightning_explain": "Per invio con transazioni istantanee",
"add_lndhub": "Connetti al tuo LNDHub",
"add_lndhub_error": "L'indirizzo fornito è un nodo LNDHub invalido.",
"add_lndhub": "Connetti al tuo LNDhub",
"add_lndhub_error": "L'indirizzo fornito è un nodo LNDhub invalido.",
"add_lndhub_placeholder": "L'indirizzo del tuo nodo",
"add_placeholder": "Il mio primo wallet",
"add_title": "Aggiungi Portafoglio",

View File

@ -247,7 +247,7 @@
"use_ssl": "SSLを使用",
"electrum_saved": "変更は正常に保存されました。変更の適用には、リスタートが必要な場合があります。",
"set_electrum_server_as_default": "{server} をデフォルトの Electrum サーバーに設定しますか?",
"set_lndhub_as_default": "{url} をデフォルトの LNDHub サーバーに設定しますか?",
"set_lndhub_as_default": "{url} をデフォルトの LNDhub サーバーに設定しますか?",
"electrum_settings_server": "Electrum サーバー",
"electrum_settings_explain": "空欄の場合デフォルトを使用します。",
"electrum_status": "ステータス",
@ -272,7 +272,7 @@
"biometrics_fail": "もし {type} が有効でない、または解除に失敗した場合、デバイスのパスコードを代わりに使うことができます。",
"general": "一般情報",
"general_adv_mode": "上級者モード",
"general_adv_mode_e": "この機能を有効にすると、異なるウォレットタイプ、接続先の LNDHub インスタンスの指定、ウォレット作成時のカスタムエントロピーなどの高度なオプションが表示されます。",
"general_adv_mode_e": "この機能を有効にすると、異なるウォレットタイプ、接続先の LNDhub インスタンスの指定、ウォレット作成時のカスタムエントロピーなどの高度なオプションが表示されます。",
"general_continuity": "継続性",
"general_continuity_e": "この機能を有効にすると、Apple iCloudに接続している他のデバイスを使用して、選択したウォレットやトランザクションを表示できるようになります。",
"groundcontrol_explanation": "GroundControlはビットコインウォレットのための無料のオープンソースのプッシュ通知サーバーです。独自のGroundControlサーバーをインストールし、BlueWalletのインフラに依存しないようにURLをここに入力することができます。デフォルトを使用するには空白のままにしてください。",
@ -284,7 +284,7 @@
"lightning_error_lndhub_uri": "無効なLndHub URIです",
"lightning_saved": "変更は正常に保存されました",
"lightning_settings": "Lightning 設定",
"lightning_settings_explain": "他の LND ノードへ接続するには LNDHub をインストール後、URL を入力してください。指定した LNDHub へ接続するのは変更保存後に作成されたウォレットのみですので注意してください。",
"lightning_settings_explain": "他の LND ノードへ接続するには LNDhub をインストール後、URL を入力してください。指定した LNDhub へ接続するのは変更保存後に作成されたウォレットのみですので注意してください。",
"network": "ネットワーク",
"network_broadcast": "ブロードキャストトランザクション",
"network_electrum": "Electrum サーバー",

View File

@ -204,7 +204,7 @@
"use_ssl": "SSL 사용",
"electrum_saved": "변경된 내용이 성공적으로 저장되었습니다. 변경사항이 적용되기 위해선 블루월렛의 재시동이 필요할 수도 있습니다.",
"set_electrum_server_as_default": "{server}를 기본 일렉트럼 서버로 설정하시겠습니까?",
"set_lndhub_as_default": "{url}을 기본 LNDHub 서버로 설정하시겠습니까?",
"set_lndhub_as_default": "{url}을 기본 LNDhub 서버로 설정하시겠습니까?",
"electrum_settings_server": "일렉트럼 서버",
"electrum_settings_explain": "기본값을 사용하려면 공란으로 남겨주세요",
"electrum_status": "상태",
@ -227,7 +227,7 @@
"encrypt_use_expl": "거래를 하거나 지갑을 해제, 내보내기, 또는 지우기 전에 신분확인을 위해 {type}이 사용될 것입니다. 암호화된 저장장치를 해제하는되는 사용되지 않을 것 입니다.",
"general": "일반",
"general_adv_mode": "고급 모드",
"general_adv_mode_e": "사용가능으로 설정시, 다른 지갑 형태, 연결하고픈 LNDHub 인스턴스를 지정할 수 있는 능력, 그리고 지갑생성시 맞춤형 엔트로피등과 같은 고급 선택사항을 볼 수 있습니다.",
"general_adv_mode_e": "사용가능으로 설정시, 다른 지갑 형태, 연결하고픈 LNDhub 인스턴스를 지정할 수 있는 능력, 그리고 지갑생성시 맞춤형 엔트로피등과 같은 고급 선택사항을 볼 수 있습니다.",
"general_continuity": "연속성",
"general_continuity_e": "사용가능으로 설정시, 애플 아이클라우드에 연결된 다른 기기을 사용하여 선택된 지갑들과 거래내역을 보실수 있습니다.",
"groundcontrol_explanation": "그라운드콘트롤은 비트코인 지갑을 위한 무상, 원본공개형 알림장치 서버 입니다.",
@ -325,8 +325,8 @@
"add_import_wallet": "지갑 들여오기",
"add_lightning": "라이트닝",
"add_lightning_explain": "즉시 거래를 통한 지출",
"add_lndhub": "사용자 LNDHub 연결",
"add_lndhub_error": "제공된 노드 주소는 유효한 LNDHub 노드가 아닙니다.",
"add_lndhub": "사용자 LNDhub 연결",
"add_lndhub_error": "제공된 노드 주소는 유효한 LNDhub 노드가 아닙니다.",
"add_lndhub_placeholder": "사용자 노드 주소",
"add_placeholder": "내 첫 지갑",
"add_title": "지갑 추가",

View File

@ -99,7 +99,7 @@
"electrum_offline_mode": "هالت آفلاین",
"use_ssl": "SSL نه وه کار بییر",
"set_electrum_server_as_default": "{server} سی سرور پؽش فرز الکترام ساموݩ بۊئه؟",
"set_lndhub_as_default": "{server} سی سرور پؽش فرز LNDHub ساموݩ بۊئه؟",
"set_lndhub_as_default": "{server} سی سرور پؽش فرز LNDhub ساموݩ بۊئه؟",
"electrum_settings_server": "سرور الکترام",
"electrum_status": "وزیت",
"electrum_clear_alert_title": "ویرگار پاک بۊئه؟",

View File

@ -190,7 +190,7 @@
"use_ssl": "Guna SSL",
"electrum_saved": "Pengubahan oleh anda berjaya disimpan. Pemulaan semula BlueWallet mungkin diperlukan untuk perubahan itu berlaku. ",
"set_electrum_server_as_default": "Tetapkan {server} sebagai pelayan lalai Electrum?",
"set_lndhub_as_default": "Tetapkan {url} sebagai pelayan lalai LNDHub?",
"set_lndhub_as_default": "Tetapkan {url} sebagai pelayan lalai LNDhub?",
"electrum_settings_server": "Pelayan Electrum",
"electrum_settings_explain": "Kosongkan untuk mengguna nilai lalai.",
"electrum_status": "Keadaan",
@ -213,14 +213,14 @@
"encrypt_use_expl": "{type} akan digunakan untuk memperakukan keperibadian anda sebelum melakukan urus niaga, penyahkuncian, pemindahan keluar, atau pemadaman sesuatu dompet. {type} tidak akan digunakan untuk menyahkunci simpanan sulit.",
"general": "Umum",
"general_adv_mode": "Mod Lanjut",
"general_adv_mode_e": "Apabila dibolehkan, anda akan nampak pilihan lanjut seperti jenis dompet yang lain, kebolehan untuk memperincikan LNDHub yang anda mahu hubungkan, dan entropi tersendiri ketika penciptaan dompet.",
"general_adv_mode_e": "Apabila dibolehkan, anda akan nampak pilihan lanjut seperti jenis dompet yang lain, kebolehan untuk memperincikan LNDhub yang anda mahu hubungkan, dan entropi tersendiri ketika penciptaan dompet.",
"general_continuity": "Kesinambungan",
"general_continuity_e": "Apabila dibolehkan, anda akan dapat melihat dompet terpilih dan urus niaga, menggunakan peranti lain yang terhubung dengan iCloud Apple.",
"groundcontrol_explanation": "GroundControl ialah satu pelayan pemberitahuan percuma dan sumber terbuka untuk dompet Bitcoin. Anda boleh memasang pelayan GroundControl anda sendiri dan letakkan URL GrounControl di sini untuk tidak bergantung pada prasarana BlueWallet. Kosongkan untuk menggunakan pelayan lalai GroundControl.",
"header": "Tetapan",
"language": "Bahasa",
"language_isRTL": "Pemulaan semula BlueWallet diperlukan untuk pengalihan bahasa berlaku.",
"lightning_error_lndhub_uri": "URL LNDHub tidak sah",
"lightning_error_lndhub_uri": "URL LNDhub tidak sah",
"lightning_saved": "Pengubahan oleh anda berjaya disimpan.",
"lightning_settings": "Tetapan Lightning",
"network": "Rangkaian",
@ -302,8 +302,8 @@
"add_import_wallet": "Pindah masuk dompet",
"add_lightning": "Lightning",
"add_lightning_explain": "Untuk perbelanjaan dengan urusan sepantas kilat",
"add_lndhub": "Hubungkan ke LNDHub anda",
"add_lndhub_error": "Alamat nod diberi ialah nod LNDHub yang tidak sah.",
"add_lndhub": "Hubungkan ke LNDhub anda",
"add_lndhub_error": "Alamat nod diberi ialah nod LNDhub yang tidak sah.",
"add_lndhub_placeholder": "Alamat Nod Anda",
"add_title": "Tambah Dompet",
"add_wallet_name": "Nama",

View File

@ -206,7 +206,7 @@
"use_ssl": "Bruk SSL",
"electrum_saved": "Endringene dine er lagret. Det kan være nødvendig å starte BlueWallet på nytt for at endringene skal tre i kraft.",
"set_electrum_server_as_default": "Vil du angi {server} som standard Electrum-server?",
"set_lndhub_as_default": "Vil du angi {url} som standard LNDHub-server?",
"set_lndhub_as_default": "Vil du angi {url} som standard LNDhub-server?",
"electrum_settings_server": "Electrum Server",
"electrum_settings_explain": "La feltet stå tomt for å bruke standard.",
"electrum_status": "Status",
@ -229,7 +229,7 @@
"encrypt_use_expl": "{type} vil bli brukt til å bekrefte identiteten din før du foretar en transaksjon, låser opp, eksporterer eller sletter en lommebok. {type} vil ikke bli brukt til å låse opp kryptert lagring.",
"general": "Generelt",
"general_adv_mode": "Avansert Modus",
"general_adv_mode_e": "Når den er aktivert, vil du se avanserte alternativer som forskjellige lommeboktyper, muligheten til å spesifisere hvilken LNDHub-instance du ønsker å koble til, og tilpasset entropi under oppretting av lommebok.",
"general_adv_mode_e": "Når den er aktivert, vil du se avanserte alternativer som forskjellige lommeboktyper, muligheten til å spesifisere hvilken LNDhub-instance du ønsker å koble til, og tilpasset entropi under oppretting av lommebok.",
"general_continuity": "Kontinuitet",
"general_continuity_e": "Når den er aktivert, vil du kunne se utvalgte lommebøker og transaksjoner ved å bruke de andre Apple iCloud-tilkoblede enhetene dine.",
"groundcontrol_explanation": "GroundControl er en gratis, åpen kildekode push-varslingsserver for Bitcoin-lommebøker. Du kan installere din egen GroundControl-server og legge dens URL her for ikke å stole på BlueWallet sin infrastruktur. La feltet stå tomt for å bruke GroundControl sin standardserver.",
@ -237,7 +237,7 @@
"language": "Språk",
"last_updated": "Sist Oppdatert",
"language_isRTL": "Å starte BlueWallet på nytt er nødvendig for at språkorienteringen skal tre i kraft.",
"lightning_error_lndhub_uri": "Ugyldig LNDHub URI",
"lightning_error_lndhub_uri": "Ugyldig LNDhub URI",
"lightning_saved": "Endringene dine er lagret.",
"lightning_settings": "Lightning Innstillinger",
"network": "Nettverk",
@ -328,8 +328,8 @@
"add_import_wallet": "Importer lommebok",
"add_lightning": "Lightning",
"add_lightning_explain": "For betaling med umiddelbare transaksjoner",
"add_lndhub": "Koble til din LNDHub",
"add_lndhub_error": "Den oppgitte nodeadressen er en ugyldig LNDHub-node.",
"add_lndhub": "Koble til din LNDhub",
"add_lndhub_error": "Den oppgitte nodeadressen er en ugyldig LNDhub-node.",
"add_lndhub_placeholder": "Din nodeadresse",
"add_placeholder": "min første lommebok",
"add_title": "Legg til lommebok",

View File

@ -213,7 +213,7 @@
"use_ssl": "Gebruik SSL",
"electrum_saved": "Uw veranderingen zijn succesvol opgeslagen. Opnieuw opstarten kan nodig zijn om de wijzigingen door te voeren.",
"set_electrum_server_as_default": "{server} instellen als de standaard electrum server?",
"set_lndhub_as_default": "{url} instellen als de standaard LNDHub server?",
"set_lndhub_as_default": "{url} instellen als de standaard LNDhub server?",
"electrum_settings_server": "Electrum Server",
"electrum_settings_explain": "Laat leeg om de standaard te gebuiken.",
"electrum_status": "Status",
@ -236,7 +236,7 @@
"encrypt_use_expl": "{type} wordt gebruikt om jouw identiteit te bevestigen voordat je een transactie uitvoert, een wallet ontgrendelt, exporteert of verwijdert. {type} wordt niet gebruikt om versleutelde opslag te ontgrendelen.",
"general": "Algemeen",
"general_adv_mode": "Geavanceerde modus",
"general_adv_mode_e": "Indien ingeschakeld ziet u geavanceerde opties zoals verschillende wallettypes, de mogelijkheid om de LNDHub-instantie te specificeren waarmee u verbinding wilt maken en aangepaste entropie tijdens het aanmaken van een wallet.",
"general_adv_mode_e": "Indien ingeschakeld ziet u geavanceerde opties zoals verschillende wallettypes, de mogelijkheid om de LNDhub-instantie te specificeren waarmee u verbinding wilt maken en aangepaste entropie tijdens het aanmaken van een wallet.",
"general_continuity": "Continuïteit",
"general_continuity_e": "Indien ingeschakeld, kunt u geselecteerde wallets en transacties bekijken met uw andere Apple iCloud-apparaten.",
"groundcontrol_explanation": "GroundControl is een gratis opensource-server voor pushmeldingen voor bitcoin-wallets. U kunt uw eigen GroundControl-server installeren en de URL hier plaatsen om niet te vertrouwen op de infrastructuur van BlueWallet. Laat leeg om standaard te gebruiken",
@ -244,7 +244,7 @@
"language": "Taal",
"last_updated": "Voor het laatst ge-update op",
"language_isRTL": "Herstarten van BlueWallet is vereist voordat de taal oriëntatie van kracht wordt.",
"lightning_error_lndhub_uri": "Ongeldige LNDHub URI",
"lightning_error_lndhub_uri": "Ongeldige LNDhub URI",
"lightning_saved": "Uw wijzigingen zijn succesvol opgeslagen",
"lightning_settings": "Lightning-instellingen",
"network": "Netwerk",
@ -331,8 +331,8 @@
"add_import_wallet": "Wallet importeren",
"add_lightning": "Lightning",
"add_lightning_explain": "Voor uitgaven met directe transacties",
"add_lndhub": "Verbind met uw LNDHub",
"add_lndhub_error": "399\nHet ingevoerde node adres is een ongeldige LNDHub node.",
"add_lndhub": "Verbind met uw LNDhub",
"add_lndhub_error": "399\nHet ingevoerde node adres is een ongeldige LNDhub node.",
"add_lndhub_placeholder": "Uw node adres",
"add_placeholder": "Mijn eerste wallet",
"add_title": "Wallet toevoegen",

View File

@ -244,7 +244,7 @@
"use_ssl": "Użyj SSL",
"electrum_saved": "Zmiany zostały zachowane pomyślnie. Żeby je zobaczyć zrestartuj aplikację.",
"set_electrum_server_as_default": "Ustawić {server} jako domyślny serwer Electrum?",
"set_lndhub_as_default": "Ustawić {url} jako domyślny serwer LNDHub?",
"set_lndhub_as_default": "Ustawić {url} jako domyślny serwer LNDhub?",
"electrum_settings_server": "Serwer Electrum",
"electrum_settings_explain": "Pozostaw puste aby użyć wartości domyślnej",
"electrum_status": "Status",
@ -273,7 +273,7 @@
"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",
"general_adv_mode_e": "Gdy włączone, zobaczysz zaawansowane ustawienia takie jak np. różne typy portfeli, zdolność do określenia instancji LNDHub, z którą chcesz się połączyć oraz niestandardowej entropii w trakcie tworzenia portfela.",
"general_adv_mode_e": "Gdy włączone, zobaczysz zaawansowane ustawienia takie jak np. różne typy portfeli, zdolność do określenia instancji LNDhub, z którą chcesz się połączyć oraz niestandardowej entropii w trakcie tworzenia portfela.",
"general_continuity": "Funkcja Continuity",
"general_continuity_e": "Gdy włączone, będziesz miał podgląd do wybranych portfeli i transakcji przy użyciu swoich urządzeń zalogowanych do Apple iCloud. ",
"groundcontrol_explanation": "GroundControl jest darmowym, open source'owym serwerem powiadomień push dla portfeli bitcoin. Możesz zainstalować swój własny serwer GroundControl i podać jego URL tutaj aby nie polegać na infrastrukturze BlueWallet. Zostaw puste by użyć domyślnej wartości.",
@ -282,10 +282,10 @@
"last_updated": "Ostatnia aktualizacja",
"language_isRTL": "Aby ustawienia dotyczące kierunku pisma wybranego języka zaczęły obowiązywać, BlueWallet musi być zrestartowany.",
"license": "Licencja",
"lightning_error_lndhub_uri": "Nieprawidłowy adres LNDHub",
"lightning_error_lndhub_uri": "Nieprawidłowy adres LNDhub",
"lightning_saved": "Wprowadzone przez ciebie zmiany zostały pomyślnie zachowane.",
"lightning_settings": "Ustawienia Lightning",
"lightning_settings_explain": "Aby połączyć się z własnym węzłem LND, zainstaluj LNDHub i wpisz jego adres URL w ustawieniach. Pamiętaj, że portfele utworzone po tej zmianie będą łączyć się z podanym serwerem LNDHub.",
"lightning_settings_explain": "Aby połączyć się z własnym węzłem LND, zainstaluj LNDhub i wpisz jego adres URL w ustawieniach. Pamiętaj, że portfele utworzone po tej zmianie będą łączyć się z podanym serwerem LNDhub.",
"network": "Sieć",
"network_broadcast": "Rozgłoś transakcję",
"network_electrum": "Serwer Electrum",
@ -390,7 +390,7 @@
"add_lightning": "Lightning",
"add_lightning_explain": "W celu wydawania za pomocą natychmiastowych transakcji",
"add_lndhub": "Podłącz do własnego LNDHuba",
"add_lndhub_error": "Podany adres nie jest prawidłowym węzłem LNDHub.",
"add_lndhub_error": "Podany adres nie jest prawidłowym węzłem LNDhub.",
"add_lndhub_placeholder": "Adres twojego węzła",
"add_placeholder": "mój pierwszy portfel",
"add_title": "Dodaj portfel",

View File

@ -245,7 +245,7 @@
"use_ssl": "Usar SSL",
"electrum_saved": "Suas alterações foram salvas com sucesso. Pode ser necessário reiniciar para que as alterações tenham efeito.",
"set_electrum_server_as_default": "Definir {server} como servidor Electrum padrão?",
"set_lndhub_as_default": "Definir {server} como servidor LNDHub padrão?",
"set_lndhub_as_default": "Definir {server} como servidor LNDhub padrão?",
"electrum_settings_server": "Servidor Electrum",
"electrum_settings_explain": "Deixe em branco para usar o padrão.",
"electrum_status": "Status",
@ -270,7 +270,7 @@
"biometrics_fail": "Se {type} não estiver habilitado ou falhar ao desbloquear, você pode usar o código de acesso do seu dispositivo como alternativa.",
"general": "Geral",
"general_adv_mode": "Modo Avançado",
"general_adv_mode_e": "Quando ativado, você verá opções avançadas, como diferentes tipos de carteira, a capacidade de especificar a instância do LNDHub à qual deseja se conectar e a entropia personalizada durante a criação da carteira.",
"general_adv_mode_e": "Quando ativado, você verá opções avançadas, como diferentes tipos de carteira, a capacidade de especificar a instância do LNDhub à qual deseja se conectar e a entropia personalizada durante a criação da carteira.",
"general_continuity": "Continuidade",
"general_continuity_e": "Quando ativado, você poderá visualizar carteiras selecionadas e transações, usando seus outros dispositivos conectados ao Apple iCloud.",
"groundcontrol_explanation": "GroundControl é um servidor de notificações push de código aberto gratuito para carteiras Bitcoin. Você pode instalar seu próprio servidor GroundControl e colocar sua URL aqui para não depender da infraestrutura da BlueWallet. Deixe em branco para usar o padrão",
@ -279,10 +279,10 @@
"last_updated": "Última Atualização",
"language_isRTL": "É necessário reiniciar a BlueWallet para que a nova orientação linguística seja ativada.",
"license": "Licença",
"lightning_error_lndhub_uri": "URI LNDHub inválida",
"lightning_error_lndhub_uri": "URI LNDhub inválida",
"lightning_saved": "Suas alterações foram salvas com sucesso.",
"lightning_settings": "Configurações Lightning",
"lightning_settings_explain": "Para se conectar ao seu próprio node LND, instale LNDHub e copie seu URL para cá. Somente carteiras criadas após salvar as alterações se conectarão com a instância LNDHub especificada.",
"lightning_settings_explain": "Para se conectar ao seu próprio node LND, instale LNDhub e copie seu URL para cá. Somente carteiras criadas após salvar as alterações se conectarão com a instância LNDhub especificada.",
"network": "Rede",
"network_broadcast": "Transmitir Transação",
"network_electrum": "Servidor Electrum",
@ -379,8 +379,8 @@
"add_import_wallet": "Importar carteira",
"add_lightning": "Lightning",
"add_lightning_explain": "Para gastar com transações instantâneas",
"add_lndhub": "Conectar ao seu LNDHub",
"add_lndhub_error": "O endereço do nó fornecido é um nó LNDHub inválido",
"add_lndhub": "Conectar ao seu LNDhub",
"add_lndhub_error": "O endereço do nó fornecido é um nó LNDhub inválido",
"add_lndhub_placeholder": "Seu endereço de nó",
"add_placeholder": "minha primeira carteira",
"add_title": "Adicionar Carteira",

View File

@ -186,7 +186,7 @@
"use_ssl": "Usar SSL",
"electrum_saved": "As alterações foram guardadas com sucesso. Pode ser necessário reiniciar para que as alterações tenham efeito.",
"set_electrum_server_as_default": "Definir {server} como servidor Electrum predefinido?",
"set_lndhub_as_default": "Definir {url} como servidor LNDHub predefinido?",
"set_lndhub_as_default": "Definir {url} como servidor LNDhub predefinido?",
"electrum_settings_server": "Electrum server",
"electrum_settings_explain": "Deixe em branco para usar a predefinição.",
"electrum_status": "Estado",
@ -207,7 +207,7 @@
"encrypt_use": "Usar {type}",
"general": "Geral",
"general_adv_mode": "Ligar modo avançado",
"general_adv_mode_e": "Quando activado, verá opções avançadas, como diferentes tipos de carteira, a capacidade de especificar a instância do LNDHub à qual se deseja conectar e a entropia personalizada durante a criação da carteira.",
"general_adv_mode_e": "Quando activado, verá opções avançadas, como diferentes tipos de carteira, a capacidade de especificar a instância do LNDhub à qual se deseja conectar e a entropia personalizada durante a criação da carteira.",
"general_continuity": "Continuidade",
"general_continuity_e": "Quando activado, poderá visualizar carteiras seleccionadas e transacções, usando os seus outros dispositivos conectados ao Apple iCloud.",
"groundcontrol_explanation": "GroundControl é um servidor de notificações push de código aberto gratuito para carteiras bitcoin. Pode instalar seu próprio servidor GroundControl e colocar sua URL aqui para não depender da infraestrutura da BlueWallet. Deixe em branco para usar o padrão",
@ -215,7 +215,7 @@
"language": "Idioma",
"last_updated": "Última atualização",
"language_isRTL": "É necessário reiniciar a BlueWallet para que a alteração de idioma tenha efeito.",
"lightning_error_lndhub_uri": "URI de LNDHub inválido",
"lightning_error_lndhub_uri": "URI de LNDhub inválido",
"lightning_saved": "As alterações foram guardadas com sucesso",
"lightning_settings": "Definições de Lightning",
"network": "Rede",
@ -292,8 +292,8 @@
"add_import_wallet": "Importar wallet",
"add_lightning": "Lightning",
"add_lightning_explain": "Para gastar com transações instantâneas",
"add_lndhub": "Conecte-se ao seu LNDHub",
"add_lndhub_error": "O endereço do nó fornecido é um nó LNDHub inválido.",
"add_lndhub": "Conecte-se ao seu LNDhub",
"add_lndhub_error": "O endereço do nó fornecido é um nó LNDhub inválido.",
"add_lndhub_placeholder": "O endereço do seu nó",
"add_placeholder": "a minha primeira carteira",
"add_title": "Adicionar carteira",

View File

@ -218,7 +218,7 @@
"encrypt_use_expl": "{type} va fi folosit pentru a confirma identitatea ta înainte de a face o tranzacție, de a debloca, de a exporta, sau de a șterge un portofel. {type} nu va fi folosit să deblocheze un spațiu de stocare criptat.",
"general": "General",
"general_adv_mode": "Mod avansat",
"general_adv_mode_e": "Cînd e activat, vei vedea opțiuni avansate, precum tipuri diferite de portofele, abilitatea de a specifica instanța LNDHub la care vrei să te conectezi, și entropia personalizată la crearea portofelului.",
"general_adv_mode_e": "Cînd e activat, vei vedea opțiuni avansate, precum tipuri diferite de portofele, abilitatea de a specifica instanța LNDhub la care vrei să te conectezi, și entropia personalizată la crearea portofelului.",
"general_continuity": "Continuitate",
"general_continuity_e": "Cînd e activat, vei vedea aici portofelele selectate, și tranzacțiile, folosind celelalte dispozitive ale tale Apple conectate la iCloud.",
"groundcontrol_explanation": "GroundControl este un server de notificări gratuit, open-source, pentru portofele Bitcoin. Poți instala propriul server GroundControl și să-i pui URL-ul aici pentru a nu te baza pe infrastructura BlueWallet. Lasă necompletat pentru a folosi serverul implicit al GroundControl.",
@ -226,7 +226,7 @@
"language": "Limbă",
"last_updated": "Actualizat ultima dată",
"language_isRTL": "E nevoie de restartarea BlueWallet pentru ca orientarea lingvistică să-și facă efectul.",
"lightning_error_lndhub_uri": "URI LNDHub invalid",
"lightning_error_lndhub_uri": "URI LNDhub invalid",
"lightning_saved": "Modificările tale au fost salvate cu succes.",
"lightning_settings": "Setări Lightning",
"network": "Rețea",
@ -311,7 +311,7 @@
"add_import_wallet": "Import portofel",
"add_lightning": "Lightning",
"add_lightning_explain": "Pentru cheltuirea cu tranzacții instante",
"add_lndhub": "Conectează-te la propriul LNDHub",
"add_lndhub": "Conectează-te la propriul LNDhub",
"add_lndhub_placeholder": "Adresa nodului tău",
"add_placeholder": "primul meu portofel",
"add_title": "Adaugă portofel",

View File

@ -230,7 +230,7 @@
"use_ssl": "Использовать SSL",
"electrum_saved": "Ваши изменения были успешно сохранены. Для вступления изменений в силу может потребоваться перезагрузка.",
"set_electrum_server_as_default": "Задать {server} как сервер Electrum по умолчанию?",
"set_lndhub_as_default": "Задать {url} как сервер LNDHub по умолчанию?",
"set_lndhub_as_default": "Задать {url} как сервер LNDhub по умолчанию?",
"electrum_settings_server": "Сервер Electrum",
"electrum_settings_explain": "Очистите, чтобы использовать по умолчанию.",
"electrum_status": "Статус",
@ -253,7 +253,7 @@
"encrypt_use_expl": "{type} будет использоваться для подтверждения вашей личности перед совершением транзакции, разблокировкой, экспортом или удалением кошелька. {type} не будет использоваться для открытия зашифрованного хранилища.",
"general": "Основные",
"general_adv_mode": "Включить расширенный режим",
"general_adv_mode_e": "При включении вы увидите расширенные параметры, такие как разные типы кошельков, возможность указать экземпляр LNDHub, к которому вы хотите подключиться, и пользовательскую энтропию при создании кошелька.",
"general_adv_mode_e": "При включении вы увидите расширенные параметры, такие как разные типы кошельков, возможность указать экземпляр LNDhub, к которому вы хотите подключиться, и пользовательскую энтропию при создании кошелька.",
"general_continuity": "Непрерывность",
"general_continuity_e": "Когда эта функция включена, вы сможете просматривать выбранные кошельки и транзакции, используя другие устройства, подключенные к Apple iCloud.",
"groundcontrol_explanation": "GroundControl - это бесплатный сервер push-уведомлений с открытым исходным кодом для биткойн-кошельков. Вы можете установить свой собственный сервер GroundControl и указать здесь его URL, чтобы не полагаться на инфраструктуру BlueWallet. Оставьте пустым, чтобы использовать по умолчанию",
@ -261,10 +261,10 @@
"language": "Язык",
"last_updated": "Последнее обновление",
"language_isRTL": "Перезапустите приложение для смены направления языка.",
"lightning_error_lndhub_uri": "Неверный URI LNDHub",
"lightning_error_lndhub_uri": "Неверный URI LNDhub",
"lightning_saved": "Ваши изменения были успешно сохранены",
"lightning_settings": "Настройки Lightning",
"lightning_settings_explain": "Чтобы подключиться к собственному LND, установите LNDHub и укажите его URL в настройках. Оставьте поле пустым, чтобы использовать LNDHub BlueWallet. Обратите внимание, что только кошельки, созданные после сохранения изменений, будут подключаться к указанному LNDHub.",
"lightning_settings_explain": "Чтобы подключиться к собственному LND, установите LNDhub и укажите его URL в настройках. Оставьте поле пустым, чтобы использовать LNDhub BlueWallet. Обратите внимание, что только кошельки, созданные после сохранения изменений, будут подключаться к указанному LNDhub.",
"network": "Сеть",
"network_broadcast": "Отправить транзакцию",
"network_electrum": "Electrum сервер",
@ -358,8 +358,8 @@
"add_import_wallet": "Импортировать кошелёк",
"add_lightning": "Lightning",
"add_lightning_explain": "Для мгновенных переводов",
"add_lndhub": "Подключиться к своему LNDHub",
"add_lndhub_error": "Неверный адрес LNDHub.",
"add_lndhub": "Подключиться к своему LNDhub",
"add_lndhub_error": "Неверный адрес LNDhub.",
"add_lndhub_placeholder": "Адрес хоста",
"add_placeholder": "мой первый кошелёк",
"add_title": "Добавить кошелёк",

View File

@ -233,7 +233,7 @@
"language": "භාෂාව",
"last_updated": "අවසන් වරට යාවත්කාලීන කරන ලදී",
"language_isRTL": "භාෂා දිශානතිය ක්‍රියාත්මක වීමට බ්ලූවොලට් නැවත ආරම්භ කිරීම අවශ්‍ය වේ.",
"lightning_error_lndhub_uri": "වලංගු නොවන LNDHub URI",
"lightning_error_lndhub_uri": "වලංගු නොවන LNDhub URI",
"lightning_saved": "ඔබේ වෙනස්කම් සාර්ථකව සුරැකී ඇත.",
"lightning_settings": "ලයිට්නින් සැකසුම්",
"network": "ජාල",
@ -323,8 +323,8 @@
"add_import_wallet": "මුදල් පසුම්බිය ආනයනය කරන්න",
"add_lightning": "ලයිට්නින්",
"add_lightning_explain": "ක්‍ෂණික ගනුදෙනු සමඟ වියදම් කිරීම සඳහා",
"add_lndhub": "ඔබේ LNDHub වෙත සම්බන්ධ වන්න",
"add_lndhub_error": "ලබා දී ඇති නෝඩ් ලිපිනය වලංගු නොවන LNDHub නෝඩයකි.",
"add_lndhub": "ඔබේ LNDhub වෙත සම්බන්ධ වන්න",
"add_lndhub_error": "ලබා දී ඇති නෝඩ් ලිපිනය වලංගු නොවන LNDhub නෝඩයකි.",
"add_lndhub_placeholder": "ඔබේ නෝඩ් ලිපිනය",
"add_placeholder": "මගේ පළමු මුදල් පසුම්බිය",
"add_title": "පසුම්බිය එකතු කරන්න",

View File

@ -190,7 +190,7 @@
"add_entropy_remain": "{gen} bytov vygenerovanej entropie. Zvyšných {rem} bytov sa získa zo systémového generátora náhodných čísel.",
"add_import_wallet": "Importovať peňaženku",
"add_lightning": "Lightning",
"add_lndhub": "Pripojiť sa na LNDHub",
"add_lndhub": "Pripojiť sa na LNDhub",
"add_lndhub_placeholder": "adresa uzla",
"add_title": "pridať peňaženku",
"add_wallet_name": "názov peňaženky",

View File

@ -210,7 +210,7 @@
"use_ssl": "SSL",
"electrum_saved": "Spremembe so bile uspešno shranjene. Da bodo spremembe začele veljati, bo morda potreben ponovni zagon.",
"set_electrum_server_as_default": "Želite nastaviti {server} kot privzeti electrum strežnik?",
"set_lndhub_as_default": "Želite nastaviti {url} kot privzeti LNDHub strežnik?",
"set_lndhub_as_default": "Želite nastaviti {url} kot privzeti LNDhub strežnik?",
"electrum_settings_server": "Electrum Strežnik",
"electrum_settings_explain": "Pustite prazno za uporabo privzetih nastavitev.",
"electrum_status": "Stanje",
@ -233,7 +233,7 @@
"encrypt_use_expl": "{type} bo uporabljen za potrditev vaše identitete pred izvedbo transakcije, odklepanjem, izvozom ali brisanjem denarnice. {type} ne bo uporabljen za odklepanje šifrirane shrambe.",
"general": "Splošno",
"general_adv_mode": "Napredni način",
"general_adv_mode_e": "Ko je omogočen, boste videli napredne možnosti, kot so različni tipi denarnic, možnost določitve LNDHub strežnika, s katerim se želite povezati in entropija po meri pri ustvarjanju denarnice.",
"general_adv_mode_e": "Ko je omogočen, boste videli napredne možnosti, kot so različni tipi denarnic, možnost določitve LNDhub strežnika, s katerim se želite povezati in entropija po meri pri ustvarjanju denarnice.",
"general_continuity": "Neprekinjenost",
"general_continuity_e": "Ko je omogočeno, si boste lahko ogledali izbrane denarnice in transakcije z uporabo vaših drugih naprav povezanih z Apple iCloud.",
"groundcontrol_explanation": "GroundControl je brezplačen odprtokoden strežnik potisnih obvestil za bitcoin denarnice. Da se ne zanašate na BlueWallet infrastrukturo, lahko namestite svoj strežnik GroundControl in tukaj dodate njegov URL. Pustite prazno, za uporabo privzetega.",
@ -241,7 +241,7 @@
"language": "Jezik",
"last_updated": "Posodobljeno",
"language_isRTL": "Za spremembo orientacije pisave je potreben ponovni zagon aplikacije.",
"lightning_error_lndhub_uri": "Neveljaven LNDHub URI",
"lightning_error_lndhub_uri": "Neveljaven LNDhub URI",
"lightning_saved": "Spremembe so bile uspešno shranjene",
"lightning_settings": "Lightning Nastavitve",
"network": "Omrežje",
@ -332,8 +332,8 @@
"add_import_wallet": "Uvozi denarnico",
"add_lightning": "Lightning",
"add_lightning_explain": "Za hitre vsakodnevne transakcije",
"add_lndhub": "Povežite se s svojim LNDHub-om",
"add_lndhub_error": "Podan naslov vozlišča ni veljavno vozlišče LNDHub.",
"add_lndhub": "Povežite se s svojim LNDhub-om",
"add_lndhub_error": "Podan naslov vozlišča ni veljavno vozlišče LNDhub.",
"add_lndhub_placeholder": "naslov vašega vozlišča",
"add_placeholder": "moja prva denarnica",
"add_title": "Dodajte denarnico",

View File

@ -219,7 +219,7 @@
"use_ssl": "Använd SSL",
"electrum_saved": "Dina ändringar har sparats. Starta om BlueWallet för att ändringarna ska träda i kraft.",
"set_electrum_server_as_default": "Vill du ställa in {server} som standard Electrum-server?",
"set_lndhub_as_default": "Vill du ställa in {url} som standard LNDHub-server?",
"set_lndhub_as_default": "Vill du ställa in {url} som standard LNDhub-server?",
"electrum_settings_server": "Electrum server",
"electrum_settings_explain": "Lämna tomt för att använda standardinställningen.",
"electrum_status": "Status",
@ -242,7 +242,7 @@
"encrypt_use_expl": "{type} kommer att användas för att bekräfta din identitet innan du gör en transaktion, låser upp, exporterar eller tar bort en plånbok. {type} kommer inte att användas för att låsa upp krypterad lagring.",
"general": "Allmän",
"general_adv_mode": "Enable advanced mode",
"general_adv_mode_e": "När det är aktiverat kommer du att se avancerade alternativ som olika plånbokstyper, möjligheten att ange den LNDHub-instans du vill ansluta till och anpassad entropi under skapandet av plånboken. ",
"general_adv_mode_e": "När det är aktiverat kommer du att se avancerade alternativ som olika plånbokstyper, möjligheten att ange den LNDhub-instans du vill ansluta till och anpassad entropi under skapandet av plånboken. ",
"general_continuity": "Kontinuitet",
"general_continuity_e": "När det är aktiverat kommer du att kunna se utvalda plånböcker och transaktioner med dina andra Apple iCloud-anslutna enheter.",
"groundcontrol_explanation": "GroundControl är en gratis push-meddelandeserver med öppen källkod för Bitcoin-plånböcker. Du kan installera din egen GroundControl-server och lägga in dess URL här för att inte lita på BlueWallets infrastruktur. Lämna tomt för att använda GroundControls standardserver.",
@ -250,10 +250,10 @@
"language": "Språk",
"last_updated": "Senast uppdaterad",
"language_isRTL": "Att starta om BlueWallet krävs för att språkorienteringen ska träda i kraft.",
"lightning_error_lndhub_uri": "Ogiltig LNDHub-URI",
"lightning_error_lndhub_uri": "Ogiltig LNDhub-URI",
"lightning_saved": "Dina ändringar har sparats.",
"lightning_settings": "Lightning Network",
"lightning_settings_explain": "För att ansluta till din egen LND-nod, installera LNDHub och ange dess URL här i inställningarna. Observera att endast plånböcker som skapas efter att ändringar har sparats kommer att ansluta till den angivna LNDHub.",
"lightning_settings_explain": "För att ansluta till din egen LND-nod, installera LNDhub och ange dess URL här i inställningarna. Observera att endast plånböcker som skapas efter att ändringar har sparats kommer att ansluta till den angivna LNDhub.",
"network": "Nätverk",
"network_broadcast": "Broadcasta Transaktion",
"network_electrum": "Electrum server",
@ -344,8 +344,8 @@
"add_import_wallet": "Importera plånbok",
"add_lightning": "Lightning",
"add_lightning_explain": "För utgifter med omedelbara transaktioner",
"add_lndhub": "Anslut till din LNDHub",
"add_lndhub_error": "Den angivna nodadressen är en ogiltig LNDHub-nod.",
"add_lndhub": "Anslut till din LNDhub",
"add_lndhub_error": "Den angivna nodadressen är en ogiltig LNDhub-nod.",
"add_lndhub_placeholder": "Din nodadress",
"add_placeholder": "Min första plånbok",
"add_title": "ny plånbok",

View File

@ -231,7 +231,7 @@
"add_entropy": "เอนโทรปี",
"add_import_wallet": "นำเข้ากระเป๋าสตางค์",
"add_lightning": "ไลท์นิง",
"add_lndhub": "เชื่อมต่ปไปที่ LNDHub ของท่าน",
"add_lndhub": "เชื่อมต่ปไปที่ LNDhub ของท่าน",
"add_lndhub_placeholder": "แอดเดรสของโหนดของท่าน",
"add_title": "เพิ่มกระเป๋าสตางค์",
"add_wallet_name": "ชื่อกระเป๋าสตางค์",

View File

@ -243,7 +243,7 @@
"add_entropy": "Ентропія",
"add_import_wallet": "Імпортувати гаманець",
"add_lightning": "Lightning",
"add_lndhub": "Підключитися до вашого LNDHub",
"add_lndhub": "Підключитися до вашого LNDhub",
"add_lndhub_placeholder": "Адреса Вашої Ноди",
"add_placeholder": "мій перший гаманець",
"add_title": "Додати Гаманець",

View File

@ -214,7 +214,7 @@
"use_ssl": "Sử dụng SSL",
"electrum_saved": "Những thay đổi của bạn đã được lưu thành công. Khởi động lại Bluewallet có thể được yêu cầu cho các thay đổi có hiệu lực.",
"set_electrum_server_as_default": "Đặt làm {server} máy chủ Electrum mặc định không?",
"set_lndhub_as_default": "Đặt làm {server} máy chủ LNDHub mặc định không?",
"set_lndhub_as_default": "Đặt làm {server} máy chủ LNDhub mặc định không?",
"electrum_settings_server": "Máy chủ Electrum",
"electrum_settings_explain": "Để trống để sử dụng mặc định.",
"electrum_status": " Trạng thái",
@ -237,7 +237,7 @@
"encrypt_use_expl": "{type} sẽ được dùng để xác nhận danh tính của bạn trước khi thực hiện giao dịch, mở khoá ví, xuất ví, hoặc xoá ví. {type} sẽ không được dùng để mở khoá lưu trữ được mã hoá.",
"general": "Cài đặt chung",
"general_adv_mode": "Chế độ nâng cao",
"general_adv_mode_e": "Nếu kích hoạt, bạn sẽ xem tùy chọn nâng cao như loại khác ví, khả năng xác định thể hiện LNDHub nào để kết nối, và entropy tuỳ chỉnh khi tạo ví. ",
"general_adv_mode_e": "Nếu kích hoạt, bạn sẽ xem tùy chọn nâng cao như loại khác ví, khả năng xác định thể hiện LNDhub nào để kết nối, và entropy tuỳ chỉnh khi tạo ví. ",
"general_continuity": "Sự liên tục",
"general_continuity_e": "Nếu kích hoạt, bạn sẽ xem những ví và giao dịch đã chọn trên các thiết bị Apple khác kết nối đến iCloud. ",
"groundcontrol_explanation": "GroundControl là một máy chủ đẩy thông báo có tự do và nguồn mở cho ví Bitcoin. Bạn có thể cài đặt máy chủ GroundControl riêng của mình và nhập URL của nó tại đây để không dựa vào hạ tầng của BlueWallet. Để trống để sử dụng máy chủ GroundControl mặc định.",
@ -245,10 +245,10 @@
"language": "Ngôn ngữ",
"last_updated": "Cập nhật cuối ",
"language_isRTL": "Khởi động lại BlueWallet để định hướng ngôn ngữ có hiệu lực.",
"lightning_error_lndhub_uri": "URI LNDHub không hợp lệ",
"lightning_error_lndhub_uri": "URI LNDhub không hợp lệ",
"lightning_saved": "Những thay đổi của bạn đã được lưu thành công.",
"lightning_settings": "Cài đặt Lightning",
"lightning_settings_explain": "Để kết nối node LND riêng của bạn, vui lòng cài đặt LNDHub va nhập URL của nó vào cài đặt tại đây. Xin lưu ý rằng chỉ các ví được tạo sau khi lưu các thay đổi sẽ kết nối với LNDHub được chỉ định.",
"lightning_settings_explain": "Để kết nối node LND riêng của bạn, vui lòng cài đặt LNDhub va nhập URL của nó vào cài đặt tại đây. Xin lưu ý rằng chỉ các ví được tạo sau khi lưu các thay đổi sẽ kết nối với LNDhub được chỉ định.",
"network": "Mạng",
"network_broadcast": "Phát sóng giao dịch",
"network_electrum": "Máy chủ Electrum",
@ -338,8 +338,8 @@
"add_import_wallet": "Nhập ví",
"add_lightning": "Lightning",
"add_lightning_explain": "Để chi tiêu với các giao dịch tức thời ",
"add_lndhub": "Kết nối với LNDHub của bạn",
"add_lndhub_error": "Địa chỉ cung cấp là một node LNDHub không hợp lệ.",
"add_lndhub": "Kết nối với LNDhub của bạn",
"add_lndhub_error": "Địa chỉ cung cấp là một node LNDhub không hợp lệ.",
"add_lndhub_placeholder": "Địa chỉ node của bạn",
"add_placeholder": "Ví đầu tiên của tôi",
"add_title": "Thêm ví",

View File

@ -178,7 +178,7 @@
"add_create": "Skep",
"add_entropy": "Entropie",
"add_import_wallet": "Beursie Invoer",
"add_lndhub_error": "Die voorgestelde knoop-punt se adres is 'n ongeldige LNDHub knoop-punt.",
"add_lndhub_error": "Die voorgestelde knoop-punt se adres is 'n ongeldige LNDhub knoop-punt.",
"add_lndhub_placeholder": "Jou Knoop-punt Adres",
"add_title": "skep beursie",
"add_wallet_name": "beursie naam",

View File

@ -1,7 +1,7 @@
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import React from 'react';
import navigationStyle from '../components/navigationStyle';
import navigationStyle, { CloseButtonPosition } from '../components/navigationStyle';
import { useTheme } from '../components/themes';
import loc from '../loc';
import {
@ -49,7 +49,7 @@ const AddWalletStack = () => {
name="AddWallet"
component={AddComponent}
options={navigationStyle({
headerBackVisible: false,
closeButtonPosition: CloseButtonPosition.Left,
title: loc.wallets.add_title,
})(theme)}
/>

View File

@ -22,7 +22,7 @@ import RBFBumpFee from '../screen/transactions/RBFBumpFee';
import RBFCancel from '../screen/transactions/RBFCancel';
import TransactionStatus from '../screen/transactions/TransactionStatus';
import WalletAddresses from '../screen/wallets/WalletAddresses';
import WalletDetails from '../screen/wallets/details';
import WalletDetails from '../screen/wallets/WalletDetails';
import GenerateWord from '../screen/wallets/generateWord';
import SelectWallet from '../screen/wallets/SelectWallet';
import WalletsList from '../screen/wallets/WalletsList';
@ -58,7 +58,6 @@ import SignVerifyStackRoot from './SignVerifyStack';
import ViewEditMultisigCosignersStackRoot from './ViewEditMultisigCosignersStack';
import WalletExportStack from './WalletExportStack';
import WalletXpubStackRoot from './WalletXpubStack';
import PlusIcon from '../components/icons/PlusIcon';
import SettingsButton from '../components/icons/SettingsButton';
import ExportMultisigCoordinationSetupStack from './ExportMultisigCoordinationSetupStack';
import ManageWallets from '../screen/wallets/ManageWallets';
@ -66,6 +65,7 @@ import getWalletTransactionsOptions from './helpers/getWalletTransactionsOptions
import { useSettings } from '../hooks/context/useSettings';
import { useStorage } from '../hooks/context/useStorage';
import WalletTransactions from '../screen/wallets/WalletTransactions';
import AddWalletButton from '../components/AddWalletButton';
const DetailViewStackScreensStack = () => {
const theme = useTheme();
@ -73,7 +73,6 @@ const DetailViewStackScreensStack = () => {
const { wallets } = useStorage();
const { isTotalBalanceEnabled } = useSettings();
const SaveButton = useMemo(() => <HeaderRightButton testID="SaveButton" disabled={true} title={loc.wallets.details_save} />, []);
const DetailButton = useMemo(() => <HeaderRightButton testID="DetailButton" disabled={true} title={loc.send.create_details} />, []);
const navigateToAddWallet = useCallback(() => {
@ -83,7 +82,7 @@ const DetailViewStackScreensStack = () => {
const RightBarButtons = useMemo(
() => (
<>
<PlusIcon onPress={navigateToAddWallet} />
<AddWalletButton onPress={navigateToAddWallet} />
<View style={styles.width24} />
<SettingsButton />
</>
@ -122,7 +121,6 @@ const DetailViewStackScreensStack = () => {
options={navigationStyle({
headerTitle: loc.wallets.details_title,
statusBarStyle: 'auto',
headerRight: () => SaveButton,
})(theme)}
/>
<DetailViewStack.Screen
@ -247,7 +245,11 @@ const DetailViewStackScreensStack = () => {
options={navigationStyle({ title: loc.addresses.addresses_title, statusBarStyle: 'auto' })(theme)}
/>
<DetailViewStack.Screen name="AddWalletRoot" component={AddWalletStack} options={NavigationFormModalOptions} />
<DetailViewStack.Screen
name="AddWalletRoot"
component={AddWalletStack}
options={navigationStyle({ closeButtonPosition: CloseButtonPosition.Left, ...NavigationFormModalOptions })(theme)}
/>
<DetailViewStack.Screen name="SendDetailsRoot" component={SendDetailsStack} options={NavigationDefaultOptions} />
<DetailViewStack.Screen name="LNDCreateInvoiceRoot" component={LNDCreateInvoiceRoot} options={NavigationDefaultOptions} />
<DetailViewStack.Screen name="ScanLndInvoiceRoot" component={ScanLndInvoiceRoot} options={NavigationDefaultOptions} />

11865
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{
"name": "bluewallet",
"version": "7.0.4",
"version": "7.0.5",
"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.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",
"@react-native/babel-preset": "^0.75.3",
"@react-native/eslint-config": "^0.75.3",
"@react-native/js-polyfills": "^0.75.3",
"@react-native/metro-babel-transformer": "^0.75.3",
"@react-native/typescript-config": "^0.75.3",
"@types/bip38": "^3.1.2",
"@types/bs58check": "^2.1.0",
"@types/create-hash": "^1.2.2",
@ -59,7 +59,7 @@
"android:clean": "cd android; ./gradlew clean ; cd .. ; npm run android",
"ios": "react-native run-ios",
"postinstall": "rn-nodeify --install buffer,events,process,stream,inherits,path,assert,crypto --hack; npm run releasenotes2json; npm run branch2json; npm run patches",
"patches": "patch -p1 < scripts/react-native-camera-kit.patch;",
"patches": "patch -p1 < scripts/react-native-camera-kit.patch; npx patch-package",
"test": "npm run tslint && npm run lint && npm run unit && npm run jest",
"jest": "jest tests/integration/*",
"e2e:debug-build": "detox build -c android.debug",
@ -75,7 +75,7 @@
},
"dependencies": {
"@babel/preset-env": "7.25.3",
"@bugsnag/react-native": "7.25.1",
"@bugsnag/react-native": "8.0.0",
"@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",
@ -84,15 +84,16 @@
"@react-native-async-storage/async-storage": "1.24.0",
"@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.75.2",
"@react-native-menu/menu": "https://github.com/BlueWallet/menu.git#a149bbf",
"@react-native/gradle-plugin": "^0.75.3",
"@react-native/metro-config": "0.75.3",
"@react-navigation/drawer": "6.7.2",
"@react-navigation/native": "6.1.18",
"@react-navigation/native-stack": "6.11.0",
"@remobile/react-native-qrcode-local-image": "github:BlueWallet/react-native-qrcode-local-image#31b0113110fbafcf5a5f3ca4183a563550f5c352",
"@rneui/base": "4.0.0-rc.8",
"@rneui/themed": "4.0.0-rc.8",
"@spsina/bip47": "github:BlueWallet/bip47#f4b8047",
"@spsina/bip47": "github:BlueWallet/bip47#df82345",
"aezeed": "0.0.5",
"assert": "2.1.0",
"base-x": "4.0.0",
@ -124,7 +125,7 @@
"prop-types": "15.8.1",
"react": "18.3.1",
"react-localization": "github:BlueWallet/react-localization#ae7969a",
"react-native": "0.75.2",
"react-native": "0.75.3",
"react-native-biometrics": "3.0.1",
"react-native-blue-crypto": "github:BlueWallet/react-native-blue-crypto#3cb5442",
"react-native-camera-kit": "13.0.0",
@ -152,9 +153,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.1",
"@react-native/metro-config": "0.75.2",
"react-native-safe-area-context": "4.10.9",
"react-native-reanimated": "3.15.2",
"react-native-safe-area-context": "4.11.0",
"react-native-screens": "3.34.0",
"react-native-secure-key-store": "github:BlueWallet/react-native-secure-key-store#2076b4849e88aa0a78e08bfbb4ce3923e0925cbc",
"react-native-share": "10.2.1",

View File

@ -0,0 +1,16 @@
diff --git a/node_modules/react-native-vector-icons/.DS_Store b/node_modules/react-native-vector-icons/.DS_Store
new file mode 100644
index 0000000..747936a
Binary files /dev/null and b/node_modules/react-native-vector-icons/.DS_Store differ
diff --git a/node_modules/react-native-vector-icons/Fonts/FontAwesome6_Brands.ttf b/node_modules/react-native-vector-icons/Fonts/FontAwesome6_Brands.ttf
deleted file mode 100644
index 30f55b7..0000000
Binary files a/node_modules/react-native-vector-icons/Fonts/FontAwesome6_Brands.ttf and /dev/null differ
diff --git a/node_modules/react-native-vector-icons/Fonts/FontAwesome6_Regular.ttf b/node_modules/react-native-vector-icons/Fonts/FontAwesome6_Regular.ttf
deleted file mode 100644
index c79589d..0000000
Binary files a/node_modules/react-native-vector-icons/Fonts/FontAwesome6_Regular.ttf and /dev/null differ
diff --git a/node_modules/react-native-vector-icons/Fonts/FontAwesome6_Solid.ttf b/node_modules/react-native-vector-icons/Fonts/FontAwesome6_Solid.ttf
deleted file mode 100644
index e479fb2..0000000
Binary files a/node_modules/react-native-vector-icons/Fonts/FontAwesome6_Solid.ttf and /dev/null differ

View File

@ -18,7 +18,7 @@ import { parse } from 'url'; // eslint-disable-line n/no-deprecated-api
import { btcToSatoshi, fiatToBTC, satoshiToBTC } from '../../blue_modules/currency';
import triggerHapticFeedback, { HapticFeedbackTypes } from '../../blue_modules/hapticFeedback';
import Notifications from '../../blue_modules/notifications';
import { BlueDismissKeyboardInputAccessory, BlueLoading } from '../../BlueComponents';
import { BlueLoading } from '../../BlueComponents';
import Lnurl from '../../class/lnurl';
import presentAlert from '../../components/Alert';
import AmountInput from '../../components/AmountInput';
@ -30,6 +30,7 @@ import loc, { formatBalance, formatBalancePlain, formatBalanceWithoutSuffix } fr
import { BitcoinUnit, Chain } from '../../models/bitcoinUnits';
import * as NavigationService from '../../NavigationService';
import { useStorage } from '../../hooks/context/useStorage';
import { DismissKeyboardInputAccessory, DismissKeyboardInputAccessoryViewID } from '../../components/DismissKeyboardInputAccessory';
const LNDCreateInvoice = () => {
const { wallets, saveToDisk, setSelectedWalletID } = useStorage();
@ -403,7 +404,7 @@ const LNDCreateInvoice = () => {
onChangeText={setAmount}
disabled={isLoading || (lnurlParams && lnurlParams.fixed)}
unit={unit}
inputAccessoryViewID={BlueDismissKeyboardInputAccessory.InputAccessoryViewID}
inputAccessoryViewID={DismissKeyboardInputAccessoryViewID}
/>
<View style={[styles.fiat, styleHooks.fiat]}>
<TextInput
@ -415,11 +416,11 @@ const LNDCreateInvoice = () => {
style={styles.fiat2}
editable={!isLoading}
onSubmitEditing={Keyboard.dismiss}
inputAccessoryViewID={BlueDismissKeyboardInputAccessory.InputAccessoryViewID}
inputAccessoryViewID={DismissKeyboardInputAccessoryViewID}
/>
{lnurlParams ? null : renderScanClickable()}
</View>
<BlueDismissKeyboardInputAccessory />
<DismissKeyboardInputAccessory />
{renderCreateButton()}
</View>
{renderWalletSelectionButton()}

View File

@ -5,7 +5,7 @@ import { I18nManager, Image, ScrollView, StyleSheet, Text, TouchableOpacity, Vie
import { Icon } from '@rneui/themed';
import { btcToSatoshi, fiatToBTC, satoshiToBTC, satoshiToLocalCurrency } from '../../blue_modules/currency';
import triggerHapticFeedback, { HapticFeedbackTypes } from '../../blue_modules/hapticFeedback';
import { BlueCard, BlueDismissKeyboardInputAccessory, BlueLoading, BlueSpacing20, BlueText } from '../../BlueComponents';
import { BlueCard, BlueLoading, BlueSpacing20, BlueText } from '../../BlueComponents';
import Lnurl from '../../class/lnurl';
import presentAlert from '../../components/Alert';
import AmountInput from '../../components/AmountInput';
@ -18,6 +18,7 @@ import loc, { formatBalance, formatBalanceWithoutSuffix } from '../../loc';
import { BitcoinUnit, Chain } from '../../models/bitcoinUnits';
import { useStorage } from '../../hooks/context/useStorage';
import { useExtendedNavigation } from '../../hooks/useExtendedNavigation';
import { DismissKeyboardInputAccessory, DismissKeyboardInputAccessoryViewID } from '../../components/DismissKeyboardInputAccessory';
import { LightningCustodianWallet } from '../../class/wallets/lightning-custodian-wallet';
import { TWallet } from '../../class/wallets/types';
import { pop } from '../../NavigationService';
@ -208,9 +209,9 @@ const LnurlPay: React.FC = () => {
onChangeText={setAmount}
disabled={payload && payload.fixed}
unit={unit}
// @ts-ignore idk
inputAccessoryViewID={BlueDismissKeyboardInputAccessory.InputAccessoryViewID}
inputAccessoryViewID={DismissKeyboardInputAccessoryViewID}
/>
<DismissKeyboardInputAccessory />
<BlueText style={styles.alignSelfCenter}>
{loc.formatString(loc.lndViewInvoice.please_pay_between_and, {
min: formatBalance(payload?.min, unit),

View File

@ -5,7 +5,7 @@ import { Icon } from '@rneui/themed';
import { btcToSatoshi, fiatToBTC } from '../../blue_modules/currency';
import triggerHapticFeedback, { HapticFeedbackTypes } from '../../blue_modules/hapticFeedback';
import { BlueCard, BlueDismissKeyboardInputAccessory, BlueLoading } from '../../BlueComponents';
import { BlueCard, BlueLoading } from '../../BlueComponents';
import Lnurl from '../../class/lnurl';
import AddressInput from '../../components/AddressInput';
import presentAlert from '../../components/Alert';
@ -17,6 +17,7 @@ import { useBiometrics, unlockWithBiometrics } from '../../hooks/useBiometrics';
import loc, { formatBalanceWithoutSuffix } from '../../loc';
import { BitcoinUnit, Chain } from '../../models/bitcoinUnits';
import { useStorage } from '../../hooks/context/useStorage';
import { DismissKeyboardInputAccessory, DismissKeyboardInputAccessoryViewID } from '../../components/DismissKeyboardInputAccessory';
const ScanLndInvoice = () => {
const { wallets, fetchAndSaveWalletTransactions } = useStorage();
@ -307,7 +308,7 @@ const ScanLndInvoice = () => {
onChangeText={setAmount}
disabled={!decoded || isLoading || decoded.num_satoshis > 0}
unit={unit}
inputAccessoryViewID={BlueDismissKeyboardInputAccessory.InputAccessoryViewID}
inputAccessoryViewID={DismissKeyboardInputAccessoryViewID}
/>
</View>
@ -321,7 +322,7 @@ const ScanLndInvoice = () => {
address={destination}
isLoading={isLoading}
placeholder={loc.lnd.placeholder}
inputAccessoryViewID={BlueDismissKeyboardInputAccessory.InputAccessoryViewID}
inputAccessoryViewID={DismissKeyboardInputAccessoryViewID}
launchedBy={name}
onBlur={onBlur}
keyboardType="email-address"
@ -355,7 +356,7 @@ const ScanLndInvoice = () => {
{renderWalletSelectionButton()}
</ScrollView>
</View>
<BlueDismissKeyboardInputAccessory />
<DismissKeyboardInputAccessory />
</SafeArea>
);
};

View File

@ -1,6 +1,17 @@
import { useFocusEffect, useRoute } from '@react-navigation/native';
import React, { useCallback, useEffect, useRef, useState } from 'react';
import { BackHandler, InteractionManager, ScrollView, StyleSheet, Text, TextInput, View } from 'react-native';
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import {
BackHandler,
Image,
InteractionManager,
LayoutAnimation,
ScrollView,
StyleSheet,
Text,
TextInput,
TouchableOpacity,
View,
} from 'react-native';
import Share from 'react-native-share';
import * as BlueElectrum from '../../blue_modules/BlueElectrum';
@ -24,6 +35,9 @@ import { SuccessView } from '../send/success';
import { useStorage } from '../../hooks/context/useStorage';
import { HandOffActivityType } from '../../components/types';
import SegmentedControl from '../../components/SegmentControl';
import ToolTipMenu from '../../components/TooltipMenu';
import { Icon } from '@rneui/themed';
import { CommonToolTipActions } from '../../typings/CommonToolTipActions';
const segmentControlValues = [loc.wallets.details_address, loc.bip47.payment_code];
@ -43,9 +57,9 @@ const ReceiveDetails = () => {
const [showConfirmedBalance, setShowConfirmedBalance] = useState(false);
const [showAddress, setShowAddress] = useState(false);
const [currentTab, setCurrentTab] = useState(segmentControlValues[0]);
const { goBack, setParams } = useExtendedNavigation();
const { goBack, setParams, setOptions } = useExtendedNavigation();
const bottomModalRef = useRef(null);
const { colors } = useTheme();
const { colors, closeImage } = useTheme();
const [intervalMs, setIntervalMs] = useState(5000);
const [eta, setEta] = useState('');
const [initialConfirmed, setInitialConfirmed] = useState(0);
@ -79,15 +93,119 @@ const ReceiveDetails = () => {
},
});
const setAddressBIP21Encoded = useCallback(
addr => {
const newBip21encoded = DeeplinkSchemaMatch.bip21encode(addr);
setParams({ address: addr });
setBip21encoded(newBip21encoded);
setShowAddress(true);
},
[setParams],
);
const obtainWalletAddress = useCallback(async () => {
console.debug('receive/details - componentDidMount');
let newAddress;
if (address) {
setAddressBIP21Encoded(address);
await Notifications.tryToObtainPermissions(receiveAddressButton);
Notifications.majorTomToGroundControl([address], [], []);
} else {
if (wallet.chain === Chain.ONCHAIN) {
try {
if (!isElectrumDisabled) newAddress = await Promise.race([wallet.getAddressAsync(), sleep(1000)]);
} catch (_) {}
if (newAddress === undefined) {
// either sleep expired or getAddressAsync threw an exception
console.warn('either sleep expired or getAddressAsync threw an exception');
newAddress = wallet._getExternalAddressByIndex(wallet.getNextFreeAddressIndex());
} else {
saveToDisk(); // caching whatever getAddressAsync() generated internally
}
} else if (wallet.chain === Chain.OFFCHAIN) {
try {
await Promise.race([wallet.getAddressAsync(), sleep(1000)]);
newAddress = wallet.getAddress();
} catch (_) {}
if (newAddress === undefined) {
// either sleep expired or getAddressAsync threw an exception
console.warn('either sleep expired or getAddressAsync threw an exception');
newAddress = wallet.getAddress();
} else {
saveToDisk(); // caching whatever getAddressAsync() generated internally
}
}
setAddressBIP21Encoded(newAddress);
await Notifications.tryToObtainPermissions(receiveAddressButton);
Notifications.majorTomToGroundControl([newAddress], [], []);
}
}, [wallet, saveToDisk, address, setAddressBIP21Encoded, isElectrumDisabled, sleep]);
const onEnablePaymentsCodeSwitchValue = useCallback(() => {
if (wallet.allowBIP47()) {
wallet.switchBIP47(!wallet.isBIP47Enabled());
}
saveToDisk();
obtainWalletAddress();
}, [wallet, saveToDisk, obtainWalletAddress]);
useEffect(() => {
if (showConfirmedBalance) {
triggerHapticFeedback(HapticFeedbackTypes.NotificationSuccess);
}
}, [showConfirmedBalance]);
const toolTipActions = useMemo(() => {
const action = CommonToolTipActions.PaymentCode;
action.menuState = wallet.isBIP47Enabled();
return [action];
}, [wallet]);
const onPressMenuItem = useCallback(() => {
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
onEnablePaymentsCodeSwitchValue();
}, [onEnablePaymentsCodeSwitchValue]);
const HeaderRight = useMemo(
() => (
<ToolTipMenu isButton isMenuPrimaryAction onPressMenuItem={onPressMenuItem} actions={[toolTipActions]}>
<Icon size={22} name="more-horiz" type="material" color={colors.foregroundColor} />
</ToolTipMenu>
),
[colors.foregroundColor, onPressMenuItem, toolTipActions],
);
const handleClose = useCallback(() => {
goBack();
}, [goBack]);
const HeaderLeft = useMemo(
() => (
<TouchableOpacity
accessibilityRole="button"
accessibilityLabel={loc._.close}
style={styles.button}
onPress={handleClose}
testID="NavigationCloseButton"
>
<Image source={closeImage} />
</TouchableOpacity>
),
[closeImage, handleClose],
);
useEffect(() => {
wallet.allowBIP47() &&
!wallet.isBIP47Enabled() &&
setOptions({
headerLeft: () => (wallet.isBIP47Enabled() ? null : HeaderLeft),
headerRight: () => (wallet.isBIP47Enabled() ? HeaderLeft : HeaderRight),
});
}, [HeaderLeft, HeaderRight, colors.foregroundColor, setOptions, wallet]);
// re-fetching address balance periodically
useEffect(() => {
console.log('receive/details - useEffect');
console.debug('receive/details - useEffect');
const intervalId = setInterval(async () => {
try {
@ -95,9 +213,9 @@ const ReceiveDetails = () => {
const addressToUse = address || decoded.address;
if (!addressToUse) return;
console.log('checking address', addressToUse, 'for balance...');
console.debug('checking address', addressToUse, 'for balance...');
const balance = await BlueElectrum.getBalanceByAddress(addressToUse);
console.log('...got', balance);
console.debug('...got', balance);
if (balance.unconfirmed > 0) {
if (initialConfirmed === 0 && initialUnconfirmed === 0) {
@ -157,7 +275,7 @@ const ReceiveDetails = () => {
}
}
} catch (error) {
console.log(error);
console.debug(error);
}
}, intervalMs);
@ -209,16 +327,6 @@ const ReceiveDetails = () => {
return true;
};
const setAddressBIP21Encoded = useCallback(
addr => {
const newBip21encoded = DeeplinkSchemaMatch.bip21encode(addr);
setParams({ address: addr });
setBip21encoded(newBip21encoded);
setShowAddress(true);
},
[setParams],
);
useEffect(() => {
BackHandler.addEventListener('hardwareBackPress', handleBackButton);
@ -256,44 +364,6 @@ const ReceiveDetails = () => {
);
};
const obtainWalletAddress = useCallback(async () => {
console.log('receive/details - componentDidMount');
let newAddress;
if (address) {
setAddressBIP21Encoded(address);
await Notifications.tryToObtainPermissions(receiveAddressButton);
Notifications.majorTomToGroundControl([address], [], []);
} else {
if (wallet.chain === Chain.ONCHAIN) {
try {
if (!isElectrumDisabled) newAddress = await Promise.race([wallet.getAddressAsync(), sleep(1000)]);
} catch (_) {}
if (newAddress === undefined) {
// either sleep expired or getAddressAsync threw an exception
console.warn('either sleep expired or getAddressAsync threw an exception');
newAddress = wallet._getExternalAddressByIndex(wallet.getNextFreeAddressIndex());
} else {
saveToDisk(); // caching whatever getAddressAsync() generated internally
}
} else if (wallet.chain === Chain.OFFCHAIN) {
try {
await Promise.race([wallet.getAddressAsync(), sleep(1000)]);
newAddress = wallet.getAddress();
} catch (_) {}
if (newAddress === undefined) {
// either sleep expired or getAddressAsync threw an exception
console.warn('either sleep expired or getAddressAsync threw an exception');
newAddress = wallet.getAddress();
} else {
saveToDisk(); // caching whatever getAddressAsync() generated internally
}
}
setAddressBIP21Encoded(newAddress);
await Notifications.tryToObtainPermissions(receiveAddressButton);
Notifications.majorTomToGroundControl([newAddress], [], []);
}
}, [wallet, saveToDisk, address, setAddressBIP21Encoded, isElectrumDisabled, sleep]);
useFocusEffect(
useCallback(() => {
const task = InteractionManager.runAfterInteractions(async () => {
@ -357,7 +427,7 @@ const ReceiveDetails = () => {
const handleShareButtonPressed = () => {
Share.open({ message: currentTab === loc.wallets.details_address ? bip21encoded : wallet.getBIP47PaymentCode() }).catch(error =>
console.log(error),
console.debug(error),
);
};

View File

@ -35,7 +35,7 @@ const styles = StyleSheet.create({
borderRadius: 20,
position: 'absolute',
left: 16,
top: 44,
top: 55,
},
closeImage: {
alignSelf: 'center',

View File

@ -28,7 +28,7 @@ import RNFS from 'react-native-fs';
import { btcToSatoshi, fiatToBTC } from '../../blue_modules/currency';
import * as fs from '../../blue_modules/fs';
import triggerHapticFeedback, { HapticFeedbackTypes } from '../../blue_modules/hapticFeedback';
import { BlueDismissKeyboardInputAccessory, BlueText } from '../../BlueComponents';
import { BlueText } from '../../BlueComponents';
import { HDSegwitBech32Wallet, MultisigHDWallet, WatchOnlyWallet } from '../../class';
import DeeplinkSchemaMatch from '../../class/deeplink-schema-match';
import { AbstractHDElectrumWallet } from '../../class/wallets/abstract-hd-electrum-wallet';
@ -38,7 +38,7 @@ import AmountInput from '../../components/AmountInput';
import { BottomModalHandle } from '../../components/BottomModal';
import Button from '../../components/Button';
import CoinsSelected from '../../components/CoinsSelected';
import InputAccessoryAllFunds from '../../components/InputAccessoryAllFunds';
import InputAccessoryAllFunds, { InputAccessoryAllFundsAccessoryViewID } from '../../components/InputAccessoryAllFunds';
import { useTheme } from '../../components/themes';
import ToolTipMenu from '../../components/TooltipMenu';
import { requestCameraAuthorization, scanQrHelper } from '../../helpers/scan-qr';
@ -56,6 +56,7 @@ import { useStorage } from '../../hooks/context/useStorage';
import { Action } from '../../components/types';
import SelectFeeModal from '../../components/SelectFeeModal';
import { useKeyboard } from '../../hooks/useKeyboard';
import { DismissKeyboardInputAccessory, DismissKeyboardInputAccessoryViewID } from '../../components/DismissKeyboardInputAccessory';
import ActionSheet from '../ActionSheet';
interface IPaymentDestinations {
@ -110,7 +111,7 @@ const SendDetails = () => {
const [dumb, setDumb] = useState(false);
const { isEditable } = routeParams;
// if utxo is limited we use it to calculate available balance
const balance: number = utxo ? utxo.reduce((prev, curr) => prev + curr.value, 0) : wallet?.getBalance() ?? 0;
const balance: number = utxo ? utxo.reduce((prev, curr) => prev + curr.value, 0) : (wallet?.getBalance() ?? 0);
const allBalance = formatBalanceWithoutSuffix(balance, BitcoinUnit.BTC, true);
// if cutomFee is not set, we need to choose highest possible fee for wallet balance
@ -741,7 +742,7 @@ const SendDetails = () => {
const res = await DocumentPicker.pickSingle({
type:
Platform.OS === 'ios'
? ['io.bluewallet.psbt', 'io.bluewallet.psbt.txn', DocumentPicker.types.plainText, 'public.json']
? ['io.bluewallet.psbt', 'io.bluewallet.psbt.txn', DocumentPicker.types.plainText, DocumentPicker.types.json]
: [DocumentPicker.types.allFiles],
});
@ -1263,7 +1264,7 @@ const SendDetails = () => {
unit={units[index] || amountUnit}
editable={isEditable}
disabled={!isEditable}
inputAccessoryViewID={InputAccessoryAllFunds.InputAccessoryViewID}
inputAccessoryViewID={InputAccessoryAllFundsAccessoryViewID}
/>
{frozenBalance > 0 && (
@ -1292,7 +1293,7 @@ const SendDetails = () => {
address={item.address}
isLoading={isLoading}
/* @ts-ignore marcos fixme */
inputAccessoryViewID={BlueDismissKeyboardInputAccessory.InputAccessoryViewID}
inputAccessoryViewID={DismissKeyboardInputAccessoryViewID}
launchedBy={name}
editable={isEditable}
/>
@ -1340,7 +1341,7 @@ const SendDetails = () => {
editable={!isLoading}
onSubmitEditing={Keyboard.dismiss}
/* @ts-ignore marcos fixme */
inputAccessoryViewID={BlueDismissKeyboardInputAccessory.InputAccessoryViewID}
inputAccessoryViewID={DismissKeyboardInputAccessoryViewID}
/>
</View>
<TouchableOpacity
@ -1373,7 +1374,7 @@ const SendDetails = () => {
feeUnit={feeUnit || BitcoinUnit.BTC}
/>
</View>
<BlueDismissKeyboardInputAccessory />
<DismissKeyboardInputAccessory />
{Platform.select({
ios: <InputAccessoryAllFunds canUseAll={balance > 0} onUseAllPressed={onUseAllPressed} balance={String(allBalance)} />,
android: isAmountToolbarVisibleForAndroid && (

View File

@ -196,7 +196,10 @@ const PsbtWithHardwareWallet = () => {
const openSignedTransaction = async () => {
try {
const res = await DocumentPicker.pickSingle({
type: Platform.OS === 'ios' ? ['io.bluewallet.psbt', 'io.bluewallet.psbt.txn'] : [DocumentPicker.types.allFiles],
type:
Platform.OS === 'ios'
? ['io.bluewallet.psbt', 'io.bluewallet.psbt.txn', DocumentPicker.types.json]
: [DocumentPicker.types.allFiles],
});
const file = await RNFS.readFile(res.uri);
if (file) {

View File

@ -16,14 +16,7 @@ const styles = StyleSheet.create({
const GeneralSettings: React.FC = () => {
const { wallets } = useStorage();
const {
isAdvancedModeEnabled,
setIsAdvancedModeEnabledStorage,
isHandOffUseEnabled,
setIsHandOffUseEnabledAsyncStorage,
isLegacyURv1Enabled,
setIsLegacyURv1EnabledStorage,
} = useSettings();
const { isHandOffUseEnabled, setIsHandOffUseEnabledAsyncStorage, isLegacyURv1Enabled, setIsLegacyURv1EnabledStorage } = useSettings();
const { navigate } = useNavigation();
const { colors } = useTheme();
@ -64,14 +57,6 @@ const GeneralSettings: React.FC = () => {
<BlueSpacing20 />
</>
) : null}
<ListItem
Component={PressableWrapper}
title={loc.settings.general_adv_mode}
switch={{ onValueChange: setIsAdvancedModeEnabledStorage, value: isAdvancedModeEnabled, testID: 'AdvancedMode' }}
/>
<BlueCard>
<BlueText>{loc.settings.general_adv_mode_e}</BlueText>
</BlueCard>
<BlueSpacing20 />
<ListItem
Component={PressableWrapper}

View File

@ -17,15 +17,7 @@ import {
import DefaultPreference from 'react-native-default-preference';
import * as BlueElectrum from '../../blue_modules/BlueElectrum';
import triggerHapticFeedback, { HapticFeedbackTypes } from '../../blue_modules/hapticFeedback';
import {
BlueButtonLink,
BlueCard,
BlueDismissKeyboardInputAccessory,
BlueDoneAndDismissKeyboardInputAccessory,
BlueLoading,
BlueSpacing20,
BlueText,
} from '../../BlueComponents';
import { BlueButtonLink, BlueCard, BlueLoading, BlueSpacing20, BlueText } from '../../BlueComponents';
import DeeplinkSchemaMatch from '../../class/deeplink-schema-match';
import presentAlert, { AlertType } from '../../components/Alert';
import Button from '../../components/Button';
@ -34,6 +26,11 @@ import { BlueCurrentTheme } from '../../components/themes';
import { scanQrHelper } from '../../helpers/scan-qr';
import loc from '../../loc';
import { StorageContext } from '../../components/Context/StorageProvider';
import {
DoneAndDismissKeyboardInputAccessory,
DoneAndDismissKeyboardInputAccessoryViewID,
} from '../../components/DoneAndDismissKeyboardInputAccessory';
import { DismissKeyboardInputAccessory, DismissKeyboardInputAccessoryViewID } from '../../components/DismissKeyboardInputAccessory';
export default class ElectrumSettings extends Component {
static contextType = StorageContext;
@ -303,7 +300,7 @@ export default class ElectrumSettings extends Component {
autoCorrect={false}
autoCapitalize="none"
underlineColorAndroid="transparent"
inputAccessoryViewID={BlueDoneAndDismissKeyboardInputAccessory.InputAccessoryViewID}
inputAccessoryViewID={DoneAndDismissKeyboardInputAccessoryViewID}
testID="HostInput"
onFocus={() => this.setState({ isAndroidAddressKeyboardVisible: true })}
onBlur={() => this.setState({ isAndroidAddressKeyboardVisible: false })}
@ -332,7 +329,7 @@ export default class ElectrumSettings extends Component {
autoCorrect={false}
autoCapitalize="none"
keyboardType="number-pad"
inputAccessoryViewID={BlueDismissKeyboardInputAccessory.InputAccessoryViewID}
inputAccessoryViewID={DismissKeyboardInputAccessoryViewID}
testID="PortInput"
onFocus={() => this.setState({ isAndroidNumericKeyboardFocused: true })}
onBlur={() => this.setState({ isAndroidNumericKeyboardFocused: false })}
@ -361,13 +358,13 @@ export default class ElectrumSettings extends Component {
<BlueSpacing20 />
</BlueCard>
{Platform.select({
ios: <BlueDismissKeyboardInputAccessory />,
android: this.state.isAndroidNumericKeyboardFocused && <BlueDismissKeyboardInputAccessory />,
ios: <DismissKeyboardInputAccessory />,
android: this.state.isAndroidNumericKeyboardFocused && <DismissKeyboardInputAccessory />,
})}
{Platform.select({
ios: (
<BlueDoneAndDismissKeyboardInputAccessory
<DoneAndDismissKeyboardInputAccessory
onClearTapped={() => this.setState({ host: '' })}
onPasteTapped={text => {
this.setState({ host: text });
@ -376,7 +373,7 @@ export default class ElectrumSettings extends Component {
/>
),
android: this.state.isAndroidAddressKeyboardVisible && (
<BlueDoneAndDismissKeyboardInputAccessory
<DoneAndDismissKeyboardInputAccessory
onClearTapped={() => {
this.setState({ host: '' });
Keyboard.dismiss();

View File

@ -139,7 +139,7 @@ const TransactionDetails = () => {
// okay, this txid _was_ with someone using payment codes, so we show the label edit dialog
// and load user-defined alias for the pc if any
setCounterpartyLabel(counterpartyMetadata ? counterpartyMetadata[foundPaymentCode]?.label ?? '' : '');
setCounterpartyLabel(counterpartyMetadata ? (counterpartyMetadata[foundPaymentCode]?.label ?? '') : '');
setIsCounterpartyLabelVisible(true);
setPaymentCode(foundPaymentCode);
}

View File

@ -1,15 +1,15 @@
import AsyncStorage from '@react-native-async-storage/async-storage';
import { useNavigation } from '@react-navigation/native';
import React, { useEffect, useReducer } from 'react';
import React, { useCallback, useEffect, useMemo, useReducer } from 'react';
import {
ActivityIndicator,
Alert,
Keyboard,
LayoutAnimation,
Linking,
Platform,
ScrollView,
StyleSheet,
Text,
TextInput,
useColorScheme,
View,
@ -21,13 +21,15 @@ import { BlueButtonLink, BlueFormLabel, BlueSpacing20, BlueSpacing40, BlueText }
import { BlueApp, HDSegwitBech32Wallet, HDSegwitP2SHWallet, LightningCustodianWallet, SegwitP2SHWallet } from '../../class';
import presentAlert from '../../components/Alert';
import Button from '../../components/Button';
import ListItem from '../../components/ListItem';
import { useTheme } from '../../components/themes';
import WalletButton from '../../components/WalletButton';
import loc from '../../loc';
import { Chain } from '../../models/bitcoinUnits';
import { useStorage } from '../../hooks/context/useStorage';
import { useSettings } from '../../hooks/context/useSettings';
import ToolTipMenu from '../../components/TooltipMenu';
import { Icon } from '@rneui/themed';
import { CommonToolTipActions } from '../../typings/CommonToolTipActions';
import { Action } from '../../components/types';
enum ButtonSelected {
// @ts-ignore: Return later to update
@ -43,7 +45,6 @@ interface State {
selectedIndex: number;
label: string;
selectedWalletType: ButtonSelected;
backdoorPressed: number;
entropy: Buffer | undefined;
entropyButtonText: string;
}
@ -54,13 +55,12 @@ const ActionTypes = {
SET_SELECTED_INDEX: 'SET_SELECTED_INDEX',
SET_LABEL: 'SET_LABEL',
SET_SELECTED_WALLET_TYPE: 'SET_SELECTED_WALLET_TYPE',
INCREMENT_BACKDOOR_PRESSED: 'INCREMENT_BACKDOOR_PRESSED',
SET_ENTROPY: 'SET_ENTROPY',
SET_ENTROPY_BUTTON_TEXT: 'SET_ENTROPY_BUTTON_TEXT',
} as const;
type ActionTypes = (typeof ActionTypes)[keyof typeof ActionTypes];
interface Action {
interface TAction {
type: ActionTypes;
payload?: any;
}
@ -71,25 +71,22 @@ const initialState: State = {
selectedIndex: 0,
label: '',
selectedWalletType: ButtonSelected.ONCHAIN,
backdoorPressed: 1,
entropy: undefined,
entropyButtonText: loc.wallets.add_entropy_provide,
};
const walletReducer = (state: State, action: Action): State => {
const walletReducer = (state: State, action: TAction): State => {
switch (action.type) {
case ActionTypes.SET_LOADING:
return { ...state, isLoading: action.payload };
case ActionTypes.SET_WALLET_BASE_URI:
return { ...state, walletBaseURI: action.payload };
case ActionTypes.SET_SELECTED_INDEX:
return { ...state, selectedIndex: action.payload };
return { ...state, selectedIndex: action.payload, selectedWalletType: ButtonSelected.ONCHAIN };
case ActionTypes.SET_LABEL:
return { ...state, label: action.payload };
case ActionTypes.SET_SELECTED_WALLET_TYPE:
return { ...state, selectedWalletType: action.payload };
case ActionTypes.INCREMENT_BACKDOOR_PRESSED:
return { ...state, backdoorPressed: state.backdoorPressed + 1 };
case ActionTypes.SET_ENTROPY:
return { ...state, entropy: action.payload };
case ActionTypes.SET_ENTROPY_BUTTON_TEXT:
@ -111,10 +108,9 @@ const WalletsAdd: React.FC = () => {
const selectedWalletType = state.selectedWalletType;
const entropy = state.entropy;
const entropyButtonText = state.entropyButtonText;
//
const colorScheme = useColorScheme();
//
const { addWallet, saveToDisk } = useStorage();
const { isAdvancedModeEnabled } = useSettings();
const { navigate, goBack, setOptions } = useNavigation();
const stylesHook = {
advancedText: {
@ -138,20 +134,7 @@ const WalletsAdd: React.FC = () => {
},
};
useEffect(() => {
AsyncStorage.getItem(BlueApp.LNDHUB)
.then(url => (url ? setWalletBaseURI(url) : setWalletBaseURI('')))
.catch(() => setWalletBaseURI(''))
.finally(() => setIsLoading(false));
}, []);
useEffect(() => {
setOptions({
statusBarStyle: Platform.select({ ios: 'light', default: colorScheme === 'dark' ? 'light' : 'dark' }),
});
}, [colorScheme, setOptions]);
const entropyGenerated = (newEntropy: Buffer) => {
const entropyGenerated = useCallback((newEntropy: Buffer) => {
let entropyTitle;
if (!newEntropy) {
entropyTitle = loc.wallets.add_entropy_provide;
@ -162,7 +145,127 @@ const WalletsAdd: React.FC = () => {
}
setEntropy(newEntropy);
setEntropyButtonText(entropyTitle);
};
}, []);
const navigateToEntropy = useCallback(() => {
Alert.alert(
loc.wallets.add_wallet_seed_length,
loc.wallets.add_wallet_seed_length_message,
[
{
text: loc._.cancel,
onPress: () => {},
style: 'default',
},
{
text: loc.wallets.add_wallet_seed_length_12,
onPress: () => {
// @ts-ignore: Return later to update
navigate('ProvideEntropy', { onGenerated: entropyGenerated, words: 12 });
},
style: 'default',
},
{
text: loc.wallets.add_wallet_seed_length_24,
onPress: () => {
// @ts-ignore: Return later to update
navigate('ProvideEntropy', { onGenerated: entropyGenerated, words: 24 });
},
style: 'default',
},
],
{ cancelable: true },
);
}, [entropyGenerated, navigate]);
const toolTipActions = useMemo(() => {
const walletSubactions: Action[] = [
{
id: HDSegwitBech32Wallet.type,
text: `${loc.multisig.native_segwit_title}`,
subtitle: 'p2wsh/HD',
menuState: selectedIndex === 0 && selectedWalletType === ButtonSelected.ONCHAIN,
},
{
id: SegwitP2SHWallet.type,
text: `${loc.multisig.wrapped_segwit_title}`,
subtitle: 'p2sh-p2wsh/HD',
menuState: selectedIndex === 1 && selectedWalletType === ButtonSelected.ONCHAIN,
},
{
id: HDSegwitP2SHWallet.type,
text: `${loc.multisig.legacy_title}`,
subtitle: 'p2sh/non-HD',
menuState: selectedIndex === 2 && selectedWalletType === ButtonSelected.ONCHAIN,
},
{
id: LightningCustodianWallet.type,
text: LightningCustodianWallet.typeReadable,
subtitle: LightningCustodianWallet.subtitleReadable,
menuState: selectedWalletType === ButtonSelected.OFFCHAIN,
},
];
const walletAction: Action = {
id: 'wallets',
text: loc.multisig.wallet_type,
subactions: walletSubactions,
displayInline: true,
};
const entropyAction = {
...CommonToolTipActions.Entropy,
text: entropyButtonText,
};
return [walletAction, entropyAction];
}, [entropyButtonText, selectedIndex, selectedWalletType]);
const handleOnLightningButtonPressed = useCallback(() => {
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
setSelectedWalletType(ButtonSelected.OFFCHAIN);
}, []);
const HeaderRight = useMemo(
() => (
<ToolTipMenu
isButton
isMenuPrimaryAction
onPressMenuItem={(id: string) => {
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
if (id === HDSegwitBech32Wallet.type) {
setSelectedIndex(0);
} else if (id === SegwitP2SHWallet.type) {
setSelectedIndex(1);
} else if (id === HDSegwitP2SHWallet.type) {
setSelectedIndex(2);
} else if (id === LightningCustodianWallet.type) {
handleOnLightningButtonPressed();
} else if (id === CommonToolTipActions.Entropy.id) {
navigateToEntropy();
}
}}
actions={toolTipActions}
>
<Icon size={22} name="more-horiz" type="material" color={colors.foregroundColor} />
</ToolTipMenu>
),
[colors.foregroundColor, handleOnLightningButtonPressed, navigateToEntropy, toolTipActions],
);
useEffect(() => {
setOptions({
headerRight: () => HeaderRight,
statusBarStyle: Platform.select({ ios: 'light', default: colorScheme === 'dark' ? 'light' : 'dark' }),
});
}, [HeaderRight, colorScheme, colors.foregroundColor, navigateToEntropy, setOptions, toolTipActions]);
useEffect(() => {
AsyncStorage.getItem(BlueApp.LNDHUB)
.then(url => (url ? setWalletBaseURI(url) : setWalletBaseURI('')))
.catch(() => setWalletBaseURI(''))
.finally(() => setIsLoading(false));
}, []);
const setIsLoading = (value: boolean) => {
dispatch({ type: 'SET_LOADING', payload: value });
@ -184,10 +287,6 @@ const WalletsAdd: React.FC = () => {
dispatch({ type: 'SET_SELECTED_WALLET_TYPE', payload: value });
};
const setBackdoorPressed = (value: number) => {
dispatch({ type: 'INCREMENT_BACKDOOR_PRESSED', payload: value });
};
const setEntropy = (value: Buffer) => {
dispatch({ type: 'SET_ENTROPY', payload: value });
};
@ -225,7 +324,6 @@ const WalletsAdd: React.FC = () => {
} catch (e: any) {
console.log(e.toString());
presentAlert({ message: e.toString() });
goBack();
return;
}
} else {
@ -291,37 +389,6 @@ const WalletsAdd: React.FC = () => {
});
};
const navigateToEntropy = () => {
Alert.alert(
loc.wallets.add_wallet_seed_length,
loc.wallets.add_wallet_seed_length_message,
[
{
text: loc._.cancel,
onPress: () => {},
style: 'default',
},
{
text: loc.wallets.add_wallet_seed_length_12,
onPress: () => {
// @ts-ignore: Return later to update
navigate('ProvideEntropy', { onGenerated: entropyGenerated, words: 12 });
},
style: 'default',
},
{
text: loc.wallets.add_wallet_seed_length_24,
onPress: () => {
// @ts-ignore: Return later to update
navigate('ProvideEntropy', { onGenerated: entropyGenerated, words: 24 });
},
style: 'default',
},
],
{ cancelable: true },
);
};
const navigateToImportWallet = () => {
// @ts-ignore: Return later to update
navigate('ImportWallet');
@ -339,14 +406,8 @@ const WalletsAdd: React.FC = () => {
setSelectedWalletType(ButtonSelected.ONCHAIN);
};
const handleOnLightningButtonPressed = () => {
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
// @ts-ignore: Return later to update
setBackdoorPressed((prevState: number) => {
return prevState + 1;
});
Keyboard.dismiss();
setSelectedWalletType(ButtonSelected.OFFCHAIN);
const onLearnMorePressed = () => {
Linking.openURL('https://bluewallet.io/lightning/');
};
return (
@ -374,12 +435,6 @@ const WalletsAdd: React.FC = () => {
onPress={handleOnBitcoinButtonPressed}
size={styles.button}
/>
<WalletButton
buttonType="Lightning"
active={selectedWalletType === ButtonSelected.OFFCHAIN}
onPress={handleOnLightningButtonPressed}
size={styles.button}
/>
<WalletButton
buttonType="Vault"
testID="ActivateVaultButton"
@ -390,65 +445,33 @@ const WalletsAdd: React.FC = () => {
</View>
<View style={styles.advanced}>
{(() => {
if (selectedWalletType === ButtonSelected.ONCHAIN && isAdvancedModeEnabled) {
return (
<View>
<BlueSpacing20 />
<Text style={[styles.advancedText, stylesHook.advancedText]}>{loc.settings.advanced_options}</Text>
<ListItem
containerStyle={[styles.noPadding, stylesHook.noPadding]}
bottomDivider={false}
onPress={() => setSelectedIndex(0)}
title={HDSegwitBech32Wallet.typeReadable}
checkmark={selectedIndex === 0}
/>
<ListItem
containerStyle={[styles.noPadding, stylesHook.noPadding]}
bottomDivider={false}
onPress={() => setSelectedIndex(1)}
title={SegwitP2SHWallet.typeReadable}
checkmark={selectedIndex === 1}
/>
<ListItem
containerStyle={[styles.noPadding, stylesHook.noPadding]}
bottomDivider={false}
onPress={() => setSelectedIndex(2)}
title={HDSegwitP2SHWallet.typeReadable}
checkmark={selectedIndex === 2}
/>
</View>
);
} else if (selectedWalletType === ButtonSelected.OFFCHAIN) {
return (
<>
<BlueSpacing20 />
<Text style={[styles.advancedText, stylesHook.advancedText]}>{loc.settings.advanced_options}</Text>
<BlueSpacing20 />
<BlueText>{loc.wallets.add_lndhub}</BlueText>
<View style={[styles.lndUri, stylesHook.lndUri]}>
<TextInput
value={walletBaseURI}
onChangeText={setWalletBaseURI}
onSubmitEditing={Keyboard.dismiss}
placeholder={loc.wallets.add_lndhub_placeholder}
clearButtonMode="while-editing"
autoCapitalize="none"
textContentType="URL"
autoCorrect={false}
placeholderTextColor="#81868e"
style={styles.textInputCommon}
editable={!isLoading}
underlineColorAndroid="transparent"
/>
</View>
</>
);
}
})()}
{isAdvancedModeEnabled === true && selectedWalletType === ButtonSelected.ONCHAIN && !isLoading && (
<BlueButtonLink style={styles.import} title={entropyButtonText} onPress={navigateToEntropy} />
{selectedWalletType === ButtonSelected.OFFCHAIN && (
<>
<BlueSpacing20 />
<View style={styles.lndhubTitle}>
<BlueText>{loc.wallets.add_lndhub}</BlueText>
<BlueButtonLink title={loc.wallets.learn_more} onPress={onLearnMorePressed} />
</View>
<View style={[styles.lndUri, stylesHook.lndUri]}>
<TextInput
value={walletBaseURI}
onChangeText={setWalletBaseURI}
onSubmitEditing={Keyboard.dismiss}
placeholder={loc.wallets.add_lndhub_placeholder}
clearButtonMode="while-editing"
autoCapitalize="none"
textContentType="URL"
autoCorrect={false}
placeholderTextColor="#81868e"
style={styles.textInputCommon}
editable={!isLoading}
underlineColorAndroid="transparent"
/>
</View>
</>
)}
<BlueSpacing20 />
{!isLoading ? (
<>
@ -508,9 +531,6 @@ const styles = StyleSheet.create({
advanced: {
marginHorizontal: 20,
},
advancedText: {
fontWeight: '500',
},
lndUri: {
flexDirection: 'row',
borderWidth: 1,
@ -524,8 +544,10 @@ const styles = StyleSheet.create({
import: {
marginVertical: 24,
},
noPadding: {
paddingHorizontal: 0,
lndhubTitle: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
},
});

View File

@ -1,4 +1,4 @@
import React, { useEffect, useState, useRef } from 'react';
import React, { useEffect, useState, useRef, useCallback } from 'react';
import { useNavigationState, useRoute, RouteProp } from '@react-navigation/native';
import { ActivityIndicator, StyleSheet, View } from 'react-native';
import triggerHapticFeedback, { HapticFeedbackTypes } from '../../blue_modules/hapticFeedback';
@ -39,16 +39,6 @@ const SelectWallet: React.FC = () => {
const walletsCarousel = useRef(null);
const previousRouteName = useNavigationState(state => state.routes[state.routes.length - 2]?.name);
let data = !onChainRequireSend
? wallets.filter(item => item.chain === Chain.ONCHAIN)
: chainType
? wallets.filter(item => item.chain === chainType && item.allowSend())
: wallets.filter(item => item.allowSend());
if (availableWallets && availableWallets.length > 0) {
data = availableWallets;
}
const stylesHook = StyleSheet.create({
loading: {
backgroundColor: colors.background,
@ -60,11 +50,27 @@ const SelectWallet: React.FC = () => {
setIsLoading(false);
}, []);
const filterWallets = useCallback(() => {
if (availableWallets && availableWallets.length > 0) {
return availableWallets;
}
if (!onChainRequireSend && chainType === Chain.ONCHAIN) {
return wallets.filter(item => item.chain === Chain.ONCHAIN);
}
if (chainType) {
return wallets.filter(item => item.chain === chainType && item.allowSend());
}
return wallets.filter(item => item.allowSend());
}, [availableWallets, chainType, onChainRequireSend, wallets]);
useEffect(() => {
setOptions({
statusBarStyle: isLoading || data.length === 0 ? 'light' : 'auto',
statusBarStyle: isLoading || (availableWallets || filterWallets()).length === 0 ? 'light' : 'auto',
});
}, [isLoading, data.length, setOptions]);
}, [isLoading, availableWallets, setOptions, filterWallets]);
useEffect(() => {
if (!isModal) {
@ -87,7 +93,11 @@ const SelectWallet: React.FC = () => {
<ActivityIndicator />
</View>
);
} else if (data.length <= 0) {
}
const filteredWallets = filterWallets();
if (filteredWallets.length <= 0) {
return (
<SafeArea>
<View style={styles.noWallets}>
@ -97,13 +107,20 @@ const SelectWallet: React.FC = () => {
</View>
</SafeArea>
);
} else {
return (
<View style={styles.walletsCarousel}>
<WalletsCarousel data={data} scrollEnabled onPress={onPress} ref={walletsCarousel} testID="WalletsList" horizontal={false} />
</View>
);
}
return (
<View style={styles.walletsCarousel}>
<WalletsCarousel
data={filteredWallets}
scrollEnabled
onPress={onPress}
ref={walletsCarousel}
testID="WalletsList"
horizontal={false}
/>
</View>
);
};
export default SelectWallet;

View File

@ -1,4 +1,4 @@
import React, { useCallback, useRef, useState } from 'react';
import React, { useCallback, useMemo, useRef, useState } from 'react';
import { useFocusEffect, useRoute } from '@react-navigation/native';
import {
ActivityIndicator,
@ -11,7 +11,6 @@ import {
ListRenderItemInfo,
Platform,
StyleSheet,
Switch,
Text,
View,
} from 'react-native';
@ -20,12 +19,11 @@ import { isDesktop } from '../../blue_modules/environment';
import { encodeUR } from '../../blue_modules/ur';
import {
BlueButtonLink,
BlueCard,
BlueFormMultiInput,
BlueLoading,
BlueSpacing10,
BlueSpacing20,
BlueSpacing40,
BlueText,
BlueTextCentered,
} from '../../BlueComponents';
import { HDSegwitBech32Wallet, MultisigCosigner, MultisigHDWallet } from '../../class';
@ -49,14 +47,14 @@ import usePrivacy from '../../hooks/usePrivacy';
import loc from '../../loc';
import ActionSheet from '../ActionSheet';
import { useStorage } from '../../hooks/context/useStorage';
import { useSettings } from '../../hooks/context/useSettings';
import ToolTipMenu from '../../components/TooltipMenu';
import { CommonToolTipActions } from '../../typings/CommonToolTipActions';
const ViewEditMultisigCosigners: React.FC = () => {
const hasLoaded = useRef(false);
const { colors } = useTheme();
const { wallets, setWalletsWithNewOrder, isElectrumDisabled } = useStorage();
const { isBiometricUseCapableAndEnabled } = useBiometrics();
const { isAdvancedModeEnabled } = useSettings();
const { navigate, dispatch, addListener } = useExtendedNavigation();
const openScannerButtonRef = useRef();
const route = useRoute();
@ -97,6 +95,9 @@ const ViewEditMultisigCosigners: React.FC = () => {
vaultKeyText: {
color: colors.alternativeTextColor,
},
askPassphrase: {
backgroundColor: colors.lightButton,
},
vaultKeyCircleSuccess: {
backgroundColor: colors.msSuccessBG,
},
@ -523,6 +524,12 @@ const ViewEditMultisigCosigners: React.FC = () => {
const hideShareModal = () => {};
const toolTipActions = useMemo(() => {
const passphrase = CommonToolTipActions.Passphrase;
passphrase.menuState = askPassphrase;
return [passphrase];
}, [askPassphrase]);
const renderProvideMnemonicsModal = () => {
return (
<BottomModal
@ -545,18 +552,24 @@ const ViewEditMultisigCosigners: React.FC = () => {
</>
}
>
<BlueTextCentered>{loc.multisig.type_your_mnemonics}</BlueTextCentered>
<BlueSpacing20 />
<BlueFormMultiInput value={importText} onChangeText={setImportText} />
{isAdvancedModeEnabled && (
<>
<BlueSpacing10 />
<View style={styles.row}>
<BlueText>{loc.wallets.import_passphrase}</BlueText>
<Switch testID="AskPassphrase" value={askPassphrase} onValueChange={setAskPassphrase} />
</View>
</>
)}
<>
<ToolTipMenu
isButton
isMenuPrimaryAction
onPressMenuItem={(id: string) => {
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
setAskPassphrase(!askPassphrase);
}}
actions={toolTipActions}
style={[styles.askPassprase, stylesHook.askPassphrase]}
>
<Icon size={22} name="more-horiz" type="material" color={colors.foregroundColor} />
</ToolTipMenu>
<BlueTextCentered>{loc.multisig.type_your_mnemonics}</BlueTextCentered>
<BlueSpacing20 />
<BlueFormMultiInput value={importText} onChangeText={setImportText} />
</>
</BottomModal>
);
};
@ -639,10 +652,11 @@ const ViewEditMultisigCosigners: React.FC = () => {
contentInsetAdjustmentBehavior="automatic"
automaticallyAdjustContentInsets
keyExtractor={(_item, index) => `${index}`}
contentContainerStyle={styles.contentContainerStyle}
/>
<BlueSpacing10 />
{footer}
<BlueSpacing40 />
<BlueCard>{footer}</BlueCard>
<BlueSpacing20 />
{renderProvideMnemonicsModal()}
@ -665,6 +679,7 @@ const styles = StyleSheet.create({
paddingTop: 32,
minHeight: 370,
},
contentContainerStyle: { padding: 16 },
modalContent: {
padding: 22,
justifyContent: 'center',
@ -700,12 +715,8 @@ const styles = StyleSheet.create({
tipLabelText: {
fontWeight: '500',
},
row: {
flexDirection: 'row',
alignItems: 'center',
marginHorizontal: 16,
justifyContent: 'space-between',
},
askPassprase: { top: 0, left: 0, justifyContent: 'center', width: 33, height: 33, borderRadius: 33 / 2 },
});
export default ViewEditMultisigCosigners;

View File

@ -0,0 +1,710 @@
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import {
ActivityIndicator,
Alert,
I18nManager,
InteractionManager,
ScrollView,
StyleSheet,
Switch,
Text,
TextInput,
TouchableOpacity,
View,
} from 'react-native';
import { writeFileAndExport } from '../../blue_modules/fs';
import triggerHapticFeedback, { HapticFeedbackTypes } from '../../blue_modules/hapticFeedback';
import Notifications from '../../blue_modules/notifications';
import { BlueCard, BlueLoading, BlueSpacing10, BlueSpacing20, BlueText } from '../../BlueComponents';
import {
HDAezeedWallet,
HDSegwitBech32Wallet,
LegacyWallet,
MultisigHDWallet,
SegwitBech32Wallet,
SegwitP2SHWallet,
WatchOnlyWallet,
} from '../../class';
import { AbstractHDElectrumWallet } from '../../class/wallets/abstract-hd-electrum-wallet';
import { LightningCustodianWallet } from '../../class/wallets/lightning-custodian-wallet';
import presentAlert from '../../components/Alert';
import Button from '../../components/Button';
import ListItem from '../../components/ListItem';
import SaveFileButton from '../../components/SaveFileButton';
import { SecondButton } from '../../components/SecondButton';
import { useTheme } from '../../components/themes';
import prompt from '../../helpers/prompt';
import { unlockWithBiometrics, useBiometrics } from '../../hooks/useBiometrics';
import { useExtendedNavigation } from '../../hooks/useExtendedNavigation';
import loc, { formatBalanceWithoutSuffix } from '../../loc';
import { BitcoinUnit, Chain } from '../../models/bitcoinUnits';
import { useStorage } from '../../hooks/context/useStorage';
import { popToTop } from '../../NavigationService';
import { useFocusEffect, useRoute, RouteProp } from '@react-navigation/native';
import { LightningTransaction, Transaction, TWallet } from '../../class/wallets/types';
import { DetailViewStackParamList } from '../../navigation/DetailViewStackParamList';
type RouteProps = RouteProp<DetailViewStackParamList, 'WalletDetails'>;
const WalletDetails: React.FC = () => {
const { saveToDisk, wallets, deleteWallet, setSelectedWalletID, txMetadata } = useStorage();
const { isBiometricUseCapableAndEnabled } = useBiometrics();
const { walletID } = useRoute<RouteProps>().params;
const [isLoading, setIsLoading] = useState<boolean>(false);
const [backdoorPressed, setBackdoorPressed] = useState<number>(0);
const walletRef = useRef<TWallet | undefined>(wallets.find(w => w.getID() === walletID));
const wallet = walletRef.current as TWallet;
const [walletUseWithHardwareWallet, setWalletUseWithHardwareWallet] = useState<boolean>(
wallet.useWithHardwareWalletEnabled ? wallet.useWithHardwareWalletEnabled() : false,
);
const [isBIP47Enabled, setIsBIP47Enabled] = useState<boolean>(wallet.isBIP47Enabled ? wallet.isBIP47Enabled() : false);
const [isContactsVisible, setIsContactsVisible] = useState<boolean>(
(wallet.allowBIP47 && wallet.allowBIP47() && wallet.isBIP47Enabled && wallet.isBIP47Enabled()) || false,
);
const [hideTransactionsInWalletsList, setHideTransactionsInWalletsList] = useState<boolean>(
wallet.getHideTransactionsInWalletsList ? wallet.getHideTransactionsInWalletsList() : false,
);
const { setOptions, navigate, addListener } = useExtendedNavigation();
const { colors } = useTheme();
const [walletName, setWalletName] = useState<string>(wallet.getLabel());
const [masterFingerprint, setMasterFingerprint] = useState<string | undefined>();
const walletTransactionsLength = useMemo<number>(() => wallet.getTransactions().length, [wallet]);
const derivationPath = useMemo<string | null>(() => {
try {
// @ts-expect-error: Need to fix later
if (wallet.getDerivationPath) {
// @ts-expect-error: Need to fix later
const path = wallet.getDerivationPath();
return path.length > 0 ? path : null;
}
return null;
} catch (e) {
return null;
}
}, [wallet]);
const [isToolTipMenuVisible, setIsToolTipMenuVisible] = useState<boolean>(false);
const onMenuWillShow = () => setIsToolTipMenuVisible(true);
const onMenuWillHide = () => setIsToolTipMenuVisible(false);
useEffect(() => {
setIsContactsVisible(wallet.allowBIP47 && wallet.allowBIP47() && isBIP47Enabled);
}, [isBIP47Enabled, wallet]);
useFocusEffect(
useCallback(() => {
const task = InteractionManager.runAfterInteractions(() => {
if (wallet.allowMasterFingerprint && wallet.allowMasterFingerprint()) {
// @ts-expect-error: Need to fix later
if (wallet.getMasterFingerprintHex) {
// @ts-expect-error: Need to fix later
setMasterFingerprint(wallet.getMasterFingerprintHex());
}
}
});
return () => task.cancel();
}, [wallet]),
);
const stylesHook = StyleSheet.create({
textLabel1: {
color: colors.feeText,
},
textLabel2: {
color: colors.feeText,
},
textValue: {
color: colors.outputValue,
},
input: {
borderColor: colors.formBorder,
borderBottomColor: colors.formBorder,
backgroundColor: colors.inputBackgroundColor,
},
delete: {
color: isToolTipMenuVisible ? colors.buttonDisabledTextColor : '#d0021b',
},
});
useEffect(() => {
setOptions({
headerBackTitleVisible: true,
});
}, [setOptions]);
useEffect(() => {
if (wallets.some(w => w.getID() === walletID)) {
setSelectedWalletID(walletID);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [walletID]);
const navigateToOverviewAndDeleteWallet = () => {
setIsLoading(true);
let externalAddresses: string[] = [];
try {
if (wallet.getAllExternalAddresses) {
externalAddresses = wallet.getAllExternalAddresses();
}
} catch (_) {}
// @ts-ignore: ts-ify later
Notifications.unsubscribe(externalAddresses, [], []);
deleteWallet(wallet);
saveToDisk(true);
triggerHapticFeedback(HapticFeedbackTypes.NotificationSuccess);
popToTop();
};
const presentWalletHasBalanceAlert = useCallback(async () => {
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()) {
navigateToOverviewAndDeleteWallet();
} else {
triggerHapticFeedback(HapticFeedbackTypes.NotificationError);
setIsLoading(false);
presentAlert({ message: loc.wallets.details_del_wb_err });
}
} catch (_) {}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const navigateToWalletExport = () => {
navigate('WalletExportRoot', {
screen: 'WalletExport',
params: {
walletID,
},
});
};
const navigateToMultisigCoordinationSetup = () => {
navigate('ExportMultisigCoordinationSetupRoot', {
screen: 'ExportMultisigCoordinationSetup',
params: {
walletID,
},
});
};
const navigateToViewEditCosigners = () => {
navigate('ViewEditMultisigCosignersRoot', {
screen: 'ViewEditMultisigCosigners',
params: {
walletID,
},
});
};
const navigateToXPub = () =>
navigate('WalletXpubRoot', {
screen: 'WalletXpub',
params: {
walletID,
},
});
const navigateToSignVerify = () =>
navigate('SignVerifyRoot', {
screen: 'SignVerify',
params: {
walletID,
address: wallet.getAllExternalAddresses()[0], // works for both single address and HD wallets
},
});
const navigateToAddresses = () =>
navigate('WalletAddresses', {
walletID,
});
const navigateToContacts = () => navigate('PaymentCodeList', { walletID });
const exportInternals = async () => {
if (backdoorPressed < 10) return setBackdoorPressed(backdoorPressed + 1);
setBackdoorPressed(0);
if (wallet.type !== HDSegwitBech32Wallet.type) return;
const fileName = 'wallet-externals.json';
const contents = JSON.stringify(
{
_balances_by_external_index: wallet._balances_by_external_index,
_balances_by_internal_index: wallet._balances_by_internal_index,
_txs_by_external_index: wallet._txs_by_external_index,
_txs_by_internal_index: wallet._txs_by_internal_index,
_utxo: wallet._utxo,
next_free_address_index: wallet.next_free_address_index,
next_free_change_address_index: wallet.next_free_change_address_index,
internal_addresses_cache: wallet.internal_addresses_cache,
external_addresses_cache: wallet.external_addresses_cache,
_xpub: wallet._xpub,
gap_limit: wallet.gap_limit,
label: wallet.label,
_lastTxFetch: wallet._lastTxFetch,
_lastBalanceFetch: wallet._lastBalanceFetch,
},
null,
2,
);
await writeFileAndExport(fileName, contents, false);
};
const purgeTransactions = async () => {
if (backdoorPressed < 10) return setBackdoorPressed(backdoorPressed + 1);
setBackdoorPressed(0);
const msg = 'Transactions purged. Pls go to main screen and back to rerender screen';
if (wallet.type === HDSegwitBech32Wallet.type) {
wallet._txs_by_external_index = {};
wallet._txs_by_internal_index = {};
presentAlert({ message: msg });
}
// @ts-expect-error: Need to fix later
if (wallet._hdWalletInstance) {
// @ts-expect-error: Need to fix later
wallet._hdWalletInstance._txs_by_external_index = {};
// @ts-expect-error: Need to fix later
wallet._hdWalletInstance._txs_by_internal_index = {};
presentAlert({ message: msg });
}
};
const walletNameTextInputOnBlur = useCallback(async () => {
if (walletName.trim().length === 0) {
const walletLabel = wallet.getLabel();
setWalletName(walletLabel);
} else {
wallet.setLabel(walletName.trim());
try {
console.warn('saving wallet name:', walletName.trim());
await saveToDisk();
} catch (error) {
console.log((error as Error).message);
}
}
}, [wallet, walletName, saveToDisk]);
useEffect(() => {
const unsubscribe = addListener('beforeRemove', () => {
walletNameTextInputOnBlur();
});
return unsubscribe;
}, [addListener, walletName, walletNameTextInputOnBlur]);
const exportHistoryContent = useCallback(() => {
const headers = [loc.transactions.date, loc.transactions.txid, `${loc.send.create_amount} (${BitcoinUnit.BTC})`, loc.send.create_memo];
if (wallet.chain === Chain.OFFCHAIN) {
headers.push(loc.lnd.payment);
}
const rows = [headers.join(',')];
const transactions = wallet.getTransactions();
transactions.forEach((transaction: Transaction & LightningTransaction) => {
const value = formatBalanceWithoutSuffix(transaction.value || 0, BitcoinUnit.BTC, true);
let hash: string = transaction.hash || '';
let memo = (transaction.hash && txMetadata[transaction.hash]?.memo?.trim()) || '';
let status = '';
if (wallet.chain === Chain.OFFCHAIN) {
hash = transaction.payment_hash ? transaction.payment_hash.toString() : '';
memo = transaction.memo || '';
status = transaction.ispaid ? loc._.success : loc.lnd.expired;
if (typeof hash !== 'string' && (hash as any)?.type === 'Buffer' && (hash as any)?.data) {
hash = Buffer.from((hash as any).data).toString('hex');
}
}
const date = transaction.received ? new Date(transaction.received).toString() : '';
const data = [date, hash, value, memo];
if (wallet.chain === Chain.OFFCHAIN) {
data.push(status);
}
rows.push(data.join(','));
});
return rows.join('\n');
}, [wallet, txMetadata]);
const handleDeleteButtonTapped = () => {
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 && wallet.getBalance() > 0 && wallet.allowSend && wallet.allowSend()) {
presentWalletHasBalanceAlert();
} else {
navigateToOverviewAndDeleteWallet();
}
},
style: 'destructive',
},
{ text: loc.wallets.details_no_cancel, onPress: () => {}, style: 'cancel' },
],
{ cancelable: false },
);
};
const fileName = useMemo(() => {
const label = wallet.getLabel().replace(' ', '-');
return `${label}-history.csv`;
}, [wallet]);
return (
<ScrollView
automaticallyAdjustKeyboardInsets
contentInsetAdjustmentBehavior="automatic"
automaticallyAdjustContentInsets
centerContent={isLoading}
testID="WalletDetailsScroll"
>
{isLoading ? (
<BlueLoading />
) : (
<View>
<BlueCard style={styles.address}>
{(() => {
if (
[LegacyWallet.type, SegwitBech32Wallet.type, SegwitP2SHWallet.type].includes(wallet.type) ||
(wallet.type === WatchOnlyWallet.type && !wallet.isHd())
) {
return (
<>
<Text style={[styles.textLabel1, stylesHook.textLabel1]}>{loc.wallets.details_address.toLowerCase()}</Text>
<Text style={[styles.textValue, stylesHook.textValue]}>
{(() => {
// gracefully handling faulty wallets, so at least user has an option to delete the wallet
try {
return wallet.getAddress ? wallet.getAddress() : '';
} catch (error: any) {
return error.message;
}
})()}
</Text>
</>
);
}
})()}
<Text style={[styles.textLabel2, stylesHook.textLabel2]}>{loc.wallets.add_wallet_name.toLowerCase()}</Text>
<View style={[styles.input, stylesHook.input]}>
<TextInput
value={walletName}
onChangeText={(text: string) => {
setWalletName(text);
}}
onChange={event => {
const text = event.nativeEvent.text;
setWalletName(text);
}}
onBlur={walletNameTextInputOnBlur}
numberOfLines={1}
placeholderTextColor="#81868e"
style={styles.inputText}
editable={!isLoading}
underlineColorAndroid="transparent"
testID="WalletNameInput"
/>
</View>
<BlueSpacing20 />
<Text style={[styles.textLabel1, stylesHook.textLabel1]}>{loc.wallets.details_type.toLowerCase()}</Text>
<Text style={[styles.textValue, stylesHook.textValue]}>{wallet.typeReadable}</Text>
{wallet.type === MultisigHDWallet.type && (
<>
<Text style={[styles.textLabel2, stylesHook.textLabel2]}>{loc.wallets.details_multisig_type}</Text>
<BlueText>
{`${wallet.getM()} / ${wallet.getN()} (${
wallet.isNativeSegwit() ? 'native segwit' : wallet.isWrappedSegwit() ? 'wrapped segwit' : 'legacy'
})`}
</BlueText>
</>
)}
{wallet.type === MultisigHDWallet.type && (
<>
<Text style={[styles.textLabel2, stylesHook.textLabel2]}>{loc.multisig.how_many_signatures_can_bluewallet_make}</Text>
<BlueText>{wallet.howManySignaturesCanWeMake()}</BlueText>
</>
)}
{wallet.type === LightningCustodianWallet.type && (
<>
<Text style={[styles.textLabel1, stylesHook.textLabel1]}>{loc.wallets.details_connected_to.toLowerCase()}</Text>
<BlueText>{wallet.getBaseURI()}</BlueText>
</>
)}
{wallet.type === HDAezeedWallet.type && (
<>
<Text style={[styles.textLabel1, stylesHook.textLabel1]}>{loc.wallets.identity_pubkey.toLowerCase()}</Text>
<BlueText>{wallet.getIdentityPubkey()}</BlueText>
</>
)}
<BlueSpacing20 />
<>
<Text onPress={exportInternals} style={[styles.textLabel2, stylesHook.textLabel2]}>
{loc.transactions.list_title.toLowerCase()}
</Text>
<View style={styles.hardware}>
<BlueText>{loc.wallets.details_display}</BlueText>
<Switch
disabled={isToolTipMenuVisible}
value={hideTransactionsInWalletsList}
onValueChange={async (value: boolean) => {
setHideTransactionsInWalletsList(value);
if (wallet.setHideTransactionsInWalletsList) {
wallet.setHideTransactionsInWalletsList(value);
}
try {
await saveToDisk();
} catch (error: any) {
console.log(error.message);
}
}}
/>
</View>
</>
<>
<Text onPress={purgeTransactions} style={[styles.textLabel2, stylesHook.textLabel2]}>
{loc.transactions.transactions_count.toLowerCase()}
</Text>
<BlueText>{wallet.getTransactions().length}</BlueText>
</>
{wallet.allowBIP47 && wallet.allowBIP47() ? (
<>
<Text style={[styles.textLabel2, stylesHook.textLabel2]}>{loc.bip47.payment_code}</Text>
<View style={styles.hardware}>
<BlueText>{loc.bip47.purpose}</BlueText>
<Switch
value={isBIP47Enabled}
onValueChange={async (value: boolean) => {
setIsBIP47Enabled(value);
if (wallet.switchBIP47) {
wallet.switchBIP47(value);
}
try {
await saveToDisk();
} catch (error: any) {
console.log(error.message);
}
}}
testID="BIP47Switch"
/>
</View>
</>
) : null}
<View>
{wallet.type === WatchOnlyWallet.type && wallet.isHd && wallet.isHd() && (
<>
<BlueSpacing10 />
<Text style={[styles.textLabel2, stylesHook.textLabel2]}>{loc.wallets.details_advanced.toLowerCase()}</Text>
<View style={styles.hardware}>
<BlueText>{loc.wallets.details_use_with_hardware_wallet}</BlueText>
<Switch
value={walletUseWithHardwareWallet}
onValueChange={async (value: boolean) => {
setWalletUseWithHardwareWallet(value);
if (wallet.setUseWithHardwareWalletEnabled) {
wallet.setUseWithHardwareWalletEnabled(value);
}
try {
await saveToDisk();
} catch (error: any) {
console.log(error.message);
}
}}
/>
</View>
</>
)}
<View style={styles.row}>
{wallet.allowMasterFingerprint && wallet.allowMasterFingerprint() && (
<View style={styles.marginRight16}>
<Text style={[styles.textLabel2, stylesHook.textLabel2]}>{loc.wallets.details_master_fingerprint.toLowerCase()}</Text>
<BlueText>{masterFingerprint ?? <ActivityIndicator />}</BlueText>
</View>
)}
{derivationPath && (
<View>
<Text style={[styles.textLabel2, stylesHook.textLabel2]}>{loc.wallets.details_derivation_path}</Text>
<BlueText testID="DerivationPath">{derivationPath}</BlueText>
</View>
)}
</View>
</View>
</BlueCard>
{(wallet instanceof AbstractHDElectrumWallet || (wallet.type === WatchOnlyWallet.type && wallet.isHd && wallet.isHd())) && (
<ListItem disabled={isToolTipMenuVisible} onPress={navigateToAddresses} title={loc.wallets.details_show_addresses} chevron />
)}
{isContactsVisible ? (
<ListItem disabled={isToolTipMenuVisible} onPress={navigateToContacts} title={loc.bip47.contacts} chevron />
) : null}
<BlueCard style={styles.address}>
<View>
<BlueSpacing20 />
<Button
disabled={isToolTipMenuVisible}
onPress={navigateToWalletExport}
testID="WalletExport"
title={loc.wallets.details_export_backup}
/>
{walletTransactionsLength > 0 && (
<>
<BlueSpacing20 />
<SaveFileButton
onMenuWillHide={onMenuWillHide}
onMenuWillShow={onMenuWillShow}
fileName={fileName}
fileContent={exportHistoryContent()}
>
<SecondButton title={loc.wallets.details_export_history} />
</SaveFileButton>
</>
)}
{wallet.type === MultisigHDWallet.type && (
<>
<BlueSpacing20 />
<SecondButton
disabled={isToolTipMenuVisible}
onPress={navigateToMultisigCoordinationSetup}
testID="MultisigCoordinationSetup"
title={loc.multisig.export_coordination_setup.replace(/^\w/, (c: string) => c.toUpperCase())}
/>
</>
)}
{wallet.type === MultisigHDWallet.type && (
<>
<BlueSpacing20 />
<SecondButton
disabled={isToolTipMenuVisible}
onPress={navigateToViewEditCosigners}
testID="ViewEditCosigners"
title={loc.multisig.view_edit_cosigners}
/>
</>
)}
{wallet.allowXpub && wallet.allowXpub() && (
<>
<BlueSpacing20 />
<SecondButton
disabled={isToolTipMenuVisible}
onPress={navigateToXPub}
testID="XPub"
title={loc.wallets.details_show_xpub}
/>
</>
)}
{wallet.allowSignVerifyMessage && wallet.allowSignVerifyMessage() && (
<>
<BlueSpacing20 />
<SecondButton
disabled={isToolTipMenuVisible}
onPress={navigateToSignVerify}
testID="SignVerify"
title={loc.addresses.sign_title}
/>
</>
)}
<BlueSpacing20 />
<BlueSpacing20 />
<TouchableOpacity
disabled={isToolTipMenuVisible}
accessibilityRole="button"
onPress={handleDeleteButtonTapped}
testID="DeleteButton"
>
<Text textBreakStrategy="simple" style={[styles.delete, stylesHook.delete]}>{`${loc.wallets.details_delete}${' '}`}</Text>
</TouchableOpacity>
<BlueSpacing20 />
<BlueSpacing20 />
</View>
</BlueCard>
</View>
)}
</ScrollView>
);
};
const styles = StyleSheet.create({
address: {
alignItems: 'center',
flex: 1,
},
textLabel1: {
fontWeight: '500',
fontSize: 14,
marginVertical: 12,
writingDirection: I18nManager.isRTL ? 'rtl' : 'ltr',
},
textLabel2: {
fontWeight: '500',
fontSize: 14,
marginVertical: 16,
writingDirection: I18nManager.isRTL ? 'rtl' : 'ltr',
},
textValue: {
fontWeight: '500',
fontSize: 14,
},
input: {
flexDirection: 'row',
borderWidth: 1,
borderBottomWidth: 0.5,
minHeight: 44,
height: 44,
alignItems: 'center',
borderRadius: 4,
},
inputText: {
flex: 1,
marginHorizontal: 8,
minHeight: 33,
color: '#81868e',
writingDirection: I18nManager.isRTL ? 'rtl' : 'ltr',
},
hardware: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
},
delete: {
fontSize: 15,
fontWeight: '500',
textAlign: 'center',
},
row: {
flexDirection: 'row',
},
marginRight16: {
marginRight: 16,
},
});
export default WalletDetails;

View File

@ -11,7 +11,6 @@ import ListItem from '../../components/ListItem';
import SafeArea from '../../components/SafeArea';
import { useTheme } from '../../components/themes';
import loc from '../../loc';
import { useSettings } from '../../hooks/context/useSettings';
import { NativeStackNavigationProp } from '@react-navigation/native-stack';
import { useExtendedNavigation } from '../../hooks/useExtendedNavigation';
import { AddWalletStackParamList } from '../../navigation/AddWalletStack';
@ -27,7 +26,6 @@ const WalletsAddMultisig: React.FC = () => {
const [m, setM] = useState(2);
const [n, setN] = useState(3);
const [format, setFormat] = useState(MultisigHDWallet.FORMAT_P2WSH);
const { isAdvancedModeEnabled } = useSettings();
const stylesHook = StyleSheet.create({
root: {
@ -202,17 +200,16 @@ const WalletsAddMultisig: React.FC = () => {
</Text>
</Text>
</View>
{isAdvancedModeEnabled && (
<View>
<ListItem
testID="VaultAdvancedCustomize"
onPress={showAdvancedOptionsModal}
title={loc.multisig.vault_advanced_customize}
subtitle={`${getCurrentlySelectedFormat('format')}, ${getCurrentlySelectedFormat('quorum')}`}
chevron
/>
</View>
)}
<View>
<ListItem
testID="VaultAdvancedCustomize"
onPress={showAdvancedOptionsModal}
title={loc.multisig.vault_advanced_customize}
subtitle={`${getCurrentlySelectedFormat('format')}, ${getCurrentlySelectedFormat('quorum')}`}
chevron
/>
</View>
<View style={styles.buttonContainer}>
<Button
testID="LetsStart"

View File

@ -1,4 +1,4 @@
import React, { useCallback, useEffect, useRef, useState } from 'react';
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { useFocusEffect, useRoute } from '@react-navigation/native';
import {
ActivityIndicator,
@ -8,7 +8,6 @@ import {
LayoutAnimation,
Platform,
StyleSheet,
Switch,
Text,
TouchableOpacity,
View,
@ -17,7 +16,7 @@ import { Icon } from '@rneui/themed';
import A from '../../blue_modules/analytics';
import triggerHapticFeedback, { HapticFeedbackTypes } from '../../blue_modules/hapticFeedback';
import { encodeUR } from '../../blue_modules/ur';
import { BlueButtonLink, BlueFormMultiInput, BlueSpacing10, BlueSpacing20, BlueText, BlueTextCentered } from '../../BlueComponents';
import { BlueButtonLink, BlueFormMultiInput, BlueSpacing10, BlueSpacing20, BlueTextCentered } from '../../BlueComponents';
import { HDSegwitBech32Wallet, MultisigCosigner, MultisigHDWallet } from '../../class';
import presentAlert from '../../components/Alert';
import BottomModal from '../../components/BottomModal';
@ -35,15 +34,15 @@ import prompt from '../../helpers/prompt';
import usePrivacy from '../../hooks/usePrivacy';
import loc from '../../loc';
import { useStorage } from '../../hooks/context/useStorage';
import { useSettings } from '../../hooks/context/useSettings';
import { scanQrHelper } from '../../helpers/scan-qr';
import { useExtendedNavigation } from '../../hooks/useExtendedNavigation';
import ToolTipMenu from '../../components/TooltipMenu';
import { CommonToolTipActions } from '../../typings/CommonToolTipActions';
const staticCache = {};
const WalletsAddMultisigStep2 = () => {
const { addWallet, saveToDisk, isElectrumDisabled, sleep, currentSharedCosigner, setSharedCosigner } = useStorage();
const { isAdvancedModeEnabled } = useSettings();
const { colors } = useTheme();
const { navigate, navigateToWalletsList } = useExtendedNavigation();
@ -108,6 +107,9 @@ const WalletsAddMultisigStep2 = () => {
root: {
backgroundColor: colors.elevated,
},
askPassphrase: {
backgroundColor: colors.lightButton,
},
textDestination: {
color: colors.foregroundColor,
},
@ -611,6 +613,12 @@ const WalletsAddMultisigStep2 = () => {
);
};
const toolTipActions = useMemo(() => {
const passphrase = CommonToolTipActions.Passphrase;
passphrase.menuState = askPassphrase;
return [passphrase];
}, [askPassphrase]);
const renderProvideMnemonicsModal = () => {
return (
<BottomModal
@ -648,18 +656,24 @@ const WalletsAddMultisigStep2 = () => {
setAskPassphrase(false);
}}
>
<BlueTextCentered>{loc.multisig.type_your_mnemonics}</BlueTextCentered>
<BlueSpacing20 />
<BlueFormMultiInput value={importText} onChangeText={setImportText} />
{isAdvancedModeEnabled && (
<>
<BlueSpacing10 />
<View style={styles.row}>
<BlueText>{loc.wallets.import_passphrase}</BlueText>
<Switch testID="AskPassphrase" value={askPassphrase} onValueChange={setAskPassphrase} />
</View>
</>
)}
<>
<ToolTipMenu
isButton
isMenuPrimaryAction
onPressMenuItem={_id => {
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
setAskPassphrase(!askPassphrase);
}}
actions={toolTipActions}
style={[styles.askPassprase, stylesHook.askPassphrase]}
>
<Icon size={22} name="more-horiz" type="material" color={colors.foregroundColor} />
</ToolTipMenu>
<BlueTextCentered>{loc.multisig.type_your_mnemonics}</BlueTextCentered>
<BlueSpacing20 />
<BlueFormMultiInput value={importText} onChangeText={setImportText} />
</>
</BottomModal>
);
};
@ -798,6 +812,8 @@ const styles = StyleSheet.create({
paddingRight: 8,
borderRadius: 4,
},
askPassprase: { top: 0, left: 0, justifyContent: 'center', width: 33, height: 33, borderRadius: 33 / 2 },
secretContainer: {
flexDirection: I18nManager.isRTL ? 'row-reverse' : 'row',
justifyContent: 'flex-start',
@ -829,12 +845,6 @@ const styles = StyleSheet.create({
fontWeight: 'bold',
marginLeft: 8,
},
row: {
flexDirection: 'row',
alignItems: 'center',
marginHorizontal: 16,
justifyContent: 'space-between',
},
});
export default WalletsAddMultisigStep2;

View File

@ -1,663 +0,0 @@
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import {
ActivityIndicator,
Alert,
I18nManager,
InteractionManager,
Keyboard,
ScrollView,
StyleSheet,
Switch,
Text,
TextInput,
TouchableOpacity,
TouchableWithoutFeedback,
View,
} from 'react-native';
import { writeFileAndExport } from '../../blue_modules/fs';
import triggerHapticFeedback, { HapticFeedbackTypes } from '../../blue_modules/hapticFeedback';
import Notifications from '../../blue_modules/notifications';
import { BlueCard, BlueLoading, BlueSpacing10, BlueSpacing20, BlueText } from '../../BlueComponents';
import {
HDAezeedWallet,
HDSegwitBech32Wallet,
LegacyWallet,
MultisigHDWallet,
SegwitBech32Wallet,
SegwitP2SHWallet,
WatchOnlyWallet,
} from '../../class';
import { AbstractHDElectrumWallet } from '../../class/wallets/abstract-hd-electrum-wallet';
import { LightningCustodianWallet } from '../../class/wallets/lightning-custodian-wallet';
import presentAlert from '../../components/Alert';
import Button from '../../components/Button';
import HeaderRightButton from '../../components/HeaderRightButton';
import ListItem from '../../components/ListItem';
import SaveFileButton from '../../components/SaveFileButton';
import { SecondButton } from '../../components/SecondButton';
import { useTheme } from '../../components/themes';
import prompt from '../../helpers/prompt';
import { unlockWithBiometrics, useBiometrics } from '../../hooks/useBiometrics';
import { useExtendedNavigation } from '../../hooks/useExtendedNavigation';
import loc, { formatBalanceWithoutSuffix } from '../../loc';
import { BitcoinUnit, Chain } from '../../models/bitcoinUnits';
import { useSettings } from '../../hooks/context/useSettings';
import { useStorage } from '../../hooks/context/useStorage';
import { popToTop } from '../../NavigationService';
import { useRoute } from '@react-navigation/native';
const styles = StyleSheet.create({
scrollViewContent: {
flexGrow: 1,
},
address: {
alignItems: 'center',
flex: 1,
},
textLabel1: {
fontWeight: '500',
fontSize: 14,
marginVertical: 12,
writingDirection: I18nManager.isRTL ? 'rtl' : 'ltr',
},
textLabel2: {
fontWeight: '500',
fontSize: 14,
marginVertical: 16,
writingDirection: I18nManager.isRTL ? 'rtl' : 'ltr',
},
textValue: {
fontWeight: '500',
fontSize: 14,
},
input: {
flexDirection: 'row',
borderWidth: 1,
borderBottomWidth: 0.5,
minHeight: 44,
height: 44,
alignItems: 'center',
borderRadius: 4,
},
inputText: {
flex: 1,
marginHorizontal: 8,
minHeight: 33,
color: '#81868e',
writingDirection: I18nManager.isRTL ? 'rtl' : 'ltr',
},
hardware: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
},
delete: {
fontSize: 15,
fontWeight: '500',
textAlign: 'center',
},
row: {
flexDirection: 'row',
},
marginRight16: {
marginRight: 16,
},
});
const WalletDetails = () => {
const { saveToDisk, wallets, deleteWallet, setSelectedWalletID, txMetadata } = useStorage();
const { isBiometricUseCapableAndEnabled } = useBiometrics();
const { walletID } = useRoute().params;
const [isLoading, setIsLoading] = useState(false);
const [backdoorPressed, setBackdoorPressed] = useState(0);
const wallet = useRef(wallets.find(w => w.getID() === walletID)).current;
const [walletName, setWalletName] = useState(wallet.getLabel());
const [useWithHardwareWallet, setUseWithHardwareWallet] = useState(wallet.useWithHardwareWalletEnabled());
const { isAdvancedModeEnabled } = useSettings();
const [isBIP47Enabled, setIsBIP47Enabled] = useState(wallet.isBIP47Enabled());
const [isContactsVisible, setIsContactsVisible] = useState(wallet.allowBIP47() && wallet.isBIP47Enabled());
const [hideTransactionsInWalletsList, setHideTransactionsInWalletsList] = useState(!wallet.getHideTransactionsInWalletsList());
const { goBack, setOptions, navigate } = useExtendedNavigation();
const { colors } = useTheme();
const [masterFingerprint, setMasterFingerprint] = useState();
const walletTransactionsLength = useMemo(() => wallet.getTransactions().length, [wallet]);
const derivationPath = useMemo(() => {
try {
const path = wallet.getDerivationPath();
return path.length > 0 ? path : null;
} catch (e) {
return null;
}
}, [wallet]);
const [isToolTipMenuVisible, setIsToolTipMenuVisible] = useState(false);
const onMenuWillShow = () => setIsToolTipMenuVisible(true);
const onMenuWillHide = () => setIsToolTipMenuVisible(false);
useEffect(() => {
setIsContactsVisible(isBIP47Enabled);
}, [isBIP47Enabled]);
useEffect(() => {
if (isAdvancedModeEnabled && wallet.allowMasterFingerprint()) {
InteractionManager.runAfterInteractions(() => {
setMasterFingerprint(wallet.getMasterFingerprintHex());
});
}
}, [isAdvancedModeEnabled, wallet]);
const stylesHook = StyleSheet.create({
textLabel1: {
color: colors.feeText,
},
textLabel2: {
color: colors.feeText,
},
textValue: {
color: colors.outputValue,
},
input: {
borderColor: colors.formBorder,
borderBottomColor: colors.formBorder,
backgroundColor: colors.inputBackgroundColor,
},
delete: {
color: isToolTipMenuVisible ? colors.buttonDisabledTextColor : '#d0021b',
},
});
const handleSave = useCallback(() => {
setIsLoading(true);
if (walletName.trim().length > 0) {
wallet.setLabel(walletName.trim());
if (wallet.type === WatchOnlyWallet.type && wallet.isHd()) {
wallet.setUseWithHardwareWalletEnabled(useWithHardwareWallet);
}
wallet.setHideTransactionsInWalletsList(!hideTransactionsInWalletsList);
if (wallet.allowBIP47()) {
wallet.switchBIP47(isBIP47Enabled);
}
}
saveToDisk()
.then(() => {
presentAlert({ message: loc.wallets.details_wallet_updated });
goBack();
})
.catch(error => {
console.log(error.message);
setIsLoading(false);
});
}, [walletName, saveToDisk, wallet, hideTransactionsInWalletsList, useWithHardwareWallet, isBIP47Enabled, goBack]);
const SaveButton = useMemo(
() => <HeaderRightButton title={loc.wallets.details_save} onPress={handleSave} disabled={isLoading} testID="Save" />,
[isLoading, handleSave],
);
useEffect(() => {
setOptions({
headerRight: () => SaveButton,
headerBackTitleVisible: true,
});
}, [SaveButton, setOptions]);
useEffect(() => {
if (wallets.some(w => w.getID() === walletID)) {
setSelectedWalletID(walletID);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [walletID]);
const navigateToOverviewAndDeleteWallet = () => {
setIsLoading(true);
let externalAddresses = [];
try {
externalAddresses = wallet.getAllExternalAddresses();
} catch (_) {}
Notifications.unsubscribe(externalAddresses, [], []);
deleteWallet(wallet);
saveToDisk(true);
triggerHapticFeedback(HapticFeedbackTypes.NotificationSuccess);
popToTop();
};
const presentWalletHasBalanceAlert = useCallback(async () => {
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()) {
navigateToOverviewAndDeleteWallet();
} else {
triggerHapticFeedback(HapticFeedbackTypes.NotificationError);
setIsLoading(false);
presentAlert({ message: loc.wallets.details_del_wb_err });
}
} catch (_) {}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const navigateToWalletExport = () => {
navigate('WalletExportRoot', {
screen: 'WalletExport',
params: {
walletID,
},
});
};
const navigateToMultisigCoordinationSetup = () => {
navigate('ExportMultisigCoordinationSetupRoot', {
screen: 'ExportMultisigCoordinationSetup',
params: {
walletID,
},
});
};
const navigateToViewEditCosigners = () => {
navigate('ViewEditMultisigCosignersRoot', {
screen: 'ViewEditMultisigCosigners',
params: {
walletID,
},
});
};
const navigateToXPub = () =>
navigate('WalletXpubRoot', {
screen: 'WalletXpub',
params: {
walletID,
},
});
const navigateToSignVerify = () =>
navigate('SignVerifyRoot', {
screen: 'SignVerify',
params: {
walletID,
address: wallet.getAllExternalAddresses()[0], // works for both single address and HD wallets
},
});
const navigateToAddresses = () =>
navigate('WalletAddresses', {
walletID,
});
const navigateToContacts = () => navigate('PaymentCodeList', { walletID });
const exportInternals = async () => {
if (backdoorPressed < 10) return setBackdoorPressed(backdoorPressed + 1);
setBackdoorPressed(0);
if (wallet.type !== HDSegwitBech32Wallet.type) return;
const fileName = 'wallet-externals.json';
const contents = JSON.stringify(
{
_balances_by_external_index: wallet._balances_by_external_index,
_balances_by_internal_index: wallet._balances_by_internal_index,
_txs_by_external_index: wallet._txs_by_external_index,
_txs_by_internal_index: wallet._txs_by_internal_index,
_utxo: wallet._utxo,
next_free_address_index: wallet.next_free_address_index,
next_free_change_address_index: wallet.next_free_change_address_index,
internal_addresses_cache: wallet.internal_addresses_cache,
external_addresses_cache: wallet.external_addresses_cache,
_xpub: wallet._xpub,
gap_limit: wallet.gap_limit,
label: wallet.label,
_lastTxFetch: wallet._lastTxFetch,
_lastBalanceFetch: wallet._lastBalanceFetch,
},
null,
2,
);
await writeFileAndExport(fileName, contents, false);
};
const purgeTransactions = async () => {
if (backdoorPressed < 10) return setBackdoorPressed(backdoorPressed + 1);
setBackdoorPressed(0);
const msg = 'Transactions purged. Pls go to main screen and back to rerender screen';
if (wallet.type === HDSegwitBech32Wallet.type) {
wallet._txs_by_external_index = {};
wallet._txs_by_internal_index = {};
presentAlert({ message: msg });
}
if (wallet._hdWalletInstance) {
wallet._hdWalletInstance._txs_by_external_index = {};
wallet._hdWalletInstance._txs_by_internal_index = {};
presentAlert({ message: msg });
}
};
const walletNameTextInputOnBlur = () => {
if (walletName.trim().length === 0) {
const walletLabel = wallet.getLabel();
setWalletName(walletLabel);
}
};
const exportHistoryContent = useCallback(() => {
const headers = [loc.transactions.date, loc.transactions.txid, `${loc.send.create_amount} (${BitcoinUnit.BTC})`, loc.send.create_memo];
if (wallet.chain === Chain.OFFCHAIN) {
headers.push(loc.lnd.payment);
}
const rows = [headers.join(',')];
const transactions = wallet.getTransactions();
transactions.forEach(transaction => {
const value = formatBalanceWithoutSuffix(transaction.value, BitcoinUnit.BTC, true);
let hash = transaction.hash;
let memo = txMetadata[transaction.hash]?.memo?.trim() ?? '';
let status;
if (wallet.chain === Chain.OFFCHAIN) {
hash = transaction.payment_hash;
memo = transaction.description;
status = transaction.ispaid ? loc._.success : loc.lnd.expired;
if (hash?.type === 'Buffer' && hash?.data) {
hash = Buffer.from(hash.data).toString('hex');
}
}
const data = [new Date(transaction.received).toString(), hash, value, memo];
if (wallet.chain === Chain.OFFCHAIN) {
data.push(status);
}
rows.push(data.join(','));
});
return rows.join('\n');
}, [wallet, txMetadata]);
const handleDeleteButtonTapped = () => {
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();
} else {
navigateToOverviewAndDeleteWallet();
}
},
style: 'destructive',
},
{ text: loc.wallets.details_no_cancel, onPress: () => {}, style: 'cancel' },
],
{ cancelable: false },
);
};
const fileName = useMemo(() => {
const label = wallet.getLabel().replace(' ', '-');
return `${label}-history.csv`;
}, [wallet]);
return (
<ScrollView
automaticallyAdjustKeyboardInsets
contentInsetAdjustmentBehavior="automatic"
centerContent={isLoading}
contentContainerStyle={styles.scrollViewContent}
testID="WalletDetailsScroll"
>
{isLoading ? (
<BlueLoading />
) : (
<TouchableWithoutFeedback onPress={Keyboard.dismiss} accessible={false}>
<View>
<BlueCard style={styles.address}>
{(() => {
if (
[LegacyWallet.type, SegwitBech32Wallet.type, SegwitP2SHWallet.type].includes(wallet.type) ||
(wallet.type === WatchOnlyWallet.type && !wallet.isHd())
) {
return (
<>
<Text style={[styles.textLabel1, stylesHook.textLabel1]}>{loc.wallets.details_address.toLowerCase()}</Text>
<Text style={[styles.textValue, stylesHook.textValue]}>
{(() => {
// gracefully handling faulty wallets, so at least user has an option to delete the wallet
try {
return wallet.getAddress();
} catch (error) {
return error.message;
}
})()}
</Text>
</>
);
}
})()}
<Text style={[styles.textLabel2, stylesHook.textLabel2]}>{loc.wallets.add_wallet_name.toLowerCase()}</Text>
<View style={[styles.input, stylesHook.input]}>
<TextInput
value={walletName}
onChangeText={setWalletName}
onBlur={walletNameTextInputOnBlur}
numberOfLines={1}
placeholderTextColor="#81868e"
style={styles.inputText}
editable={!isLoading}
underlineColorAndroid="transparent"
testID="WalletNameInput"
/>
</View>
<BlueSpacing20 />
<Text style={[styles.textLabel1, stylesHook.textLabel1]}>{loc.wallets.details_type.toLowerCase()}</Text>
<Text style={[styles.textValue, stylesHook.textValue]}>{wallet.typeReadable}</Text>
{wallet.type === MultisigHDWallet.type && (
<>
<Text style={[styles.textLabel2, stylesHook.textLabel2]}>{loc.wallets.details_multisig_type}</Text>
<BlueText>
{`${wallet.getM()} / ${wallet.getN()} (${
wallet.isNativeSegwit() ? 'native segwit' : wallet.isWrappedSegwit() ? 'wrapped segwit' : 'legacy'
})`}
</BlueText>
</>
)}
{wallet.type === MultisigHDWallet.type && (
<>
<Text style={[styles.textLabel2, stylesHook.textLabel2]}>{loc.multisig.how_many_signatures_can_bluewallet_make}</Text>
<BlueText>{wallet.howManySignaturesCanWeMake()}</BlueText>
</>
)}
{wallet.type === LightningCustodianWallet.type && (
<>
<Text style={[styles.textLabel1, stylesHook.textLabel1]}>{loc.wallets.details_connected_to.toLowerCase()}</Text>
<BlueText>{wallet.getBaseURI()}</BlueText>
</>
)}
{wallet.type === HDAezeedWallet.type && (
<>
<Text style={[styles.textLabel1, stylesHook.textLabel1]}>{loc.wallets.identity_pubkey.toLowerCase()}</Text>
<BlueText>{wallet.getIdentityPubkey()}</BlueText>
</>
)}
<BlueSpacing20 />
<>
<Text onPress={exportInternals} style={[styles.textLabel2, stylesHook.textLabel2]}>
{loc.transactions.list_title.toLowerCase()}
</Text>
<View style={styles.hardware}>
<BlueText>{loc.wallets.details_display}</BlueText>
<Switch
disabled={isToolTipMenuVisible}
value={hideTransactionsInWalletsList}
onValueChange={setHideTransactionsInWalletsList}
/>
</View>
</>
<>
<Text onPress={purgeTransactions} style={[styles.textLabel2, stylesHook.textLabel2]}>
{loc.transactions.transactions_count.toLowerCase()}
</Text>
<BlueText>{wallet.getTransactions().length}</BlueText>
</>
{wallet.allowBIP47() ? (
<>
<Text style={[styles.textLabel2, stylesHook.textLabel2]}>{loc.bip47.payment_code}</Text>
<View style={styles.hardware}>
<BlueText>{loc.bip47.purpose}</BlueText>
<Switch value={isBIP47Enabled} onValueChange={setIsBIP47Enabled} testID="BIP47Switch" />
</View>
</>
) : null}
<View>
{wallet.type === WatchOnlyWallet.type && wallet.isHd() && (
<>
<BlueSpacing10 />
<Text style={[styles.textLabel2, stylesHook.textLabel2]}>{loc.wallets.details_advanced.toLowerCase()}</Text>
<View style={styles.hardware}>
<BlueText>{loc.wallets.details_use_with_hardware_wallet}</BlueText>
<Switch value={useWithHardwareWallet} onValueChange={setUseWithHardwareWallet} />
</View>
</>
)}
{isAdvancedModeEnabled && (
<View style={styles.row}>
{wallet.allowMasterFingerprint() && (
<View style={styles.marginRight16}>
<Text style={[styles.textLabel2, stylesHook.textLabel2]}>
{loc.wallets.details_master_fingerprint.toLowerCase()}
</Text>
<BlueText>{masterFingerprint ?? <ActivityIndicator />}</BlueText>
</View>
)}
{derivationPath && (
<View>
<Text style={[styles.textLabel2, stylesHook.textLabel2]}>{loc.wallets.details_derivation_path}</Text>
<BlueText testID="DerivationPath">{derivationPath}</BlueText>
</View>
)}
</View>
)}
</View>
</BlueCard>
{(wallet instanceof AbstractHDElectrumWallet || (wallet.type === WatchOnlyWallet.type && wallet.isHd())) && (
<ListItem disabled={isToolTipMenuVisible} onPress={navigateToAddresses} title={loc.wallets.details_show_addresses} chevron />
)}
{isContactsVisible ? (
<ListItem disabled={isToolTipMenuVisible} onPress={navigateToContacts} title={loc.bip47.contacts} chevron />
) : null}
<BlueCard style={styles.address}>
<View>
<BlueSpacing20 />
<Button
disabled={isToolTipMenuVisible}
onPress={navigateToWalletExport}
testID="WalletExport"
title={loc.wallets.details_export_backup}
/>
{walletTransactionsLength > 0 && (
<>
<BlueSpacing20 />
<SaveFileButton
onMenuWillHide={onMenuWillHide}
onMenuWillShow={onMenuWillShow}
fileName={fileName}
fileContent={exportHistoryContent()}
>
<SecondButton title={loc.wallets.details_export_history} />
</SaveFileButton>
</>
)}
{wallet.type === MultisigHDWallet.type && (
<>
<BlueSpacing20 />
<SecondButton
disabled={isToolTipMenuVisible}
onPress={navigateToMultisigCoordinationSetup}
testID="MultisigCoordinationSetup"
title={loc.multisig.export_coordination_setup.replace(/^\w/, c => c.toUpperCase())}
/>
</>
)}
{wallet.type === MultisigHDWallet.type && (
<>
<BlueSpacing20 />
<SecondButton
disabled={isToolTipMenuVisible}
onPress={navigateToViewEditCosigners}
testID="ViewEditCosigners"
title={loc.multisig.view_edit_cosigners}
/>
</>
)}
{wallet.allowXpub() && (
<>
<BlueSpacing20 />
<SecondButton
disabled={isToolTipMenuVisible}
onPress={navigateToXPub}
testID="XPub"
title={loc.wallets.details_show_xpub}
/>
</>
)}
{wallet.allowSignVerifyMessage() && (
<>
<BlueSpacing20 />
<SecondButton
disabled={isToolTipMenuVisible}
onPress={navigateToSignVerify}
testID="SignVerify"
title={loc.addresses.sign_title}
/>
</>
)}
<BlueSpacing20 />
<BlueSpacing20 />
<TouchableOpacity
disabled={isToolTipMenuVisible}
accessibilityRole="button"
onPress={handleDeleteButtonTapped}
testID="DeleteButton"
>
<Text
textBreakStrategy="simple"
style={[styles.delete, stylesHook.delete]}
>{`${loc.wallets.details_delete}${' '}`}</Text>
</TouchableOpacity>
<BlueSpacing20 />
<BlueSpacing20 />
</View>
</BlueCard>
</View>
</TouchableWithoutFeedback>
)}
</ScrollView>
);
};
export default WalletDetails;

View File

@ -1,31 +1,29 @@
import { useNavigation, useRoute } from '@react-navigation/native';
import React, { useEffect, useState } from 'react';
import { Keyboard, Platform, StyleSheet, Switch, TouchableWithoutFeedback, View } from 'react-native';
import {
BlueButtonLink,
BlueDoneAndDismissKeyboardInputAccessory,
BlueFormLabel,
BlueFormMultiInput,
BlueSpacing20,
BlueText,
} from '../../BlueComponents';
import React, { useEffect, useState, useMemo, useCallback } from 'react';
import { useRoute } from '@react-navigation/native';
import { Keyboard, Platform, StyleSheet, TouchableWithoutFeedback, View, ScrollView } from 'react-native';
import { BlueButtonLink, BlueFormLabel, BlueFormMultiInput, BlueSpacing20 } from '../../BlueComponents';
import Button from '../../components/Button';
import SafeArea from '../../components/SafeArea';
import { useTheme } from '../../components/themes';
import { requestCameraAuthorization } from '../../helpers/scan-qr';
import usePrivacy from '../../hooks/usePrivacy';
import loc from '../../loc';
import { useSettings } from '../../hooks/context/useSettings';
import {
DoneAndDismissKeyboardInputAccessory,
DoneAndDismissKeyboardInputAccessoryViewID,
} from '../../components/DoneAndDismissKeyboardInputAccessory';
import { Icon } from '@rneui/themed';
import { CommonToolTipActions } from '../../typings/CommonToolTipActions';
import { useKeyboard } from '../../hooks/useKeyboard';
import ToolTipMenu from '../../components/TooltipMenu';
import { useExtendedNavigation } from '../../hooks/useExtendedNavigation';
const WalletsImport = () => {
const navigation = useNavigation();
const navigation = useExtendedNavigation();
const { colors } = useTheme();
const route = useRoute();
const label = route?.params?.label ?? '';
const triggerImport = route?.params?.triggerImport ?? false;
const scannedData = route?.params?.scannedData ?? '';
const { isAdvancedModeEnabled } = useSettings();
const [importText, setImportText] = useState(label);
const [isToolbarVisibleForAndroid, setIsToolbarVisibleForAndroid] = useState(false);
const [, setSpeedBackdoor] = useState(0);
@ -33,23 +31,18 @@ const WalletsImport = () => {
const [askPassphrase, setAskPassphrase] = useState(false);
const { enableBlur, disableBlur } = usePrivacy();
// Styles
const styles = StyleSheet.create({
root: {
paddingTop: 10,
backgroundColor: colors.elevated,
flex: 1,
},
center: {
flex: 1,
marginHorizontal: 16,
backgroundColor: colors.elevated,
},
row: {
flexDirection: 'row',
alignItems: 'center',
marginHorizontal: 16,
marginTop: 10,
justifyContent: 'space-between',
},
});
const onBlur = () => {
@ -58,18 +51,18 @@ const WalletsImport = () => {
return valueWithSingleWhitespace;
};
useKeyboard({
onKeyboardDidShow: () => {
setIsToolbarVisibleForAndroid(true);
},
onKeyboardDidHide: () => {
setIsToolbarVisibleForAndroid(false);
},
});
useEffect(() => {
enableBlur();
const showSubscription = Keyboard.addListener(Platform.OS === 'ios' ? 'keyboardWillShow' : 'keyboardDidShow', () =>
setIsToolbarVisibleForAndroid(true),
);
const hideSubscription = Keyboard.addListener(Platform.OS === 'ios' ? 'keyboardWillHide' : 'keyboardDidHide', () =>
setIsToolbarVisibleForAndroid(false),
);
return () => {
showSubscription.remove();
hideSubscription.remove();
disableBlur();
};
}, [disableBlur, enableBlur]);
@ -125,21 +118,51 @@ const WalletsImport = () => {
});
};
const toolTipOnPressMenuItem = useCallback(
menuItem => {
if (menuItem === CommonToolTipActions.Passphrase.id) {
setAskPassphrase(!askPassphrase);
} else if (menuItem === CommonToolTipActions.SearchAccount.id) {
setSearchAccounts(!searchAccounts);
}
},
[askPassphrase, searchAccounts],
);
// ToolTipMenu actions for advanced options
const toolTipActions = useMemo(() => {
const askPassphraseAction = CommonToolTipActions.Passphrase;
askPassphraseAction.menuState = askPassphrase;
const searchAccountsAction = CommonToolTipActions.SearchAccount;
searchAccountsAction.menuState = searchAccounts;
return [askPassphraseAction, searchAccountsAction];
}, [askPassphrase, searchAccounts]);
const HeaderRight = useMemo(
() => (
<ToolTipMenu
isButton
testID="HeaderRightButton"
isMenuPrimaryAction
onPressMenuItem={toolTipOnPressMenuItem}
actions={toolTipActions}
>
<Icon size={22} name="more-horiz" type="material" color={colors.foregroundColor} />
</ToolTipMenu>
),
[toolTipOnPressMenuItem, toolTipActions, colors.foregroundColor],
);
// Adding the ToolTipMenu to the header
useEffect(() => {
navigation.setOptions({
headerRight: () => HeaderRight,
});
}, [askPassphrase, searchAccounts, colors.foregroundColor, navigation, toolTipActions, HeaderRight]);
const renderOptionsAndImportButton = (
<>
{isAdvancedModeEnabled && (
<>
<View style={styles.row}>
<BlueText>{loc.wallets.import_passphrase}</BlueText>
<Switch testID="AskPassphrase" value={askPassphrase} onValueChange={setAskPassphrase} />
</View>
<View style={styles.row}>
<BlueText>{loc.wallets.import_search_accounts}</BlueText>
<Switch testID="SearchAccounts" value={searchAccounts} onValueChange={setSearchAccounts} />
</View>
</>
)}
<BlueSpacing20 />
<View style={styles.center}>
<>
@ -157,7 +180,14 @@ const WalletsImport = () => {
);
return (
<SafeArea style={styles.root}>
<ScrollView
contentContainerStyle={styles.root}
automaticallyAdjustContentInsets
automaticallyAdjustsScrollIndicatorInsets
keyboardShouldPersistTaps="always"
automaticallyAdjustKeyboardInsets
contentInsetAdjustmentBehavior="automatic"
>
<BlueSpacing20 />
<TouchableWithoutFeedback accessibilityRole="button" onPress={speedBackdoorTap} testID="SpeedBackdoor">
<BlueFormLabel>{loc.wallets.import_explanation}</BlueFormLabel>
@ -168,13 +198,13 @@ const WalletsImport = () => {
onBlur={onBlur}
onChangeText={setImportText}
testID="MnemonicInput"
inputAccessoryViewID={BlueDoneAndDismissKeyboardInputAccessory.InputAccessoryViewID}
inputAccessoryViewID={DoneAndDismissKeyboardInputAccessoryViewID}
/>
{Platform.select({ android: !isToolbarVisibleForAndroid && renderOptionsAndImportButton, default: renderOptionsAndImportButton })}
{Platform.select({
ios: (
<BlueDoneAndDismissKeyboardInputAccessory
<DoneAndDismissKeyboardInputAccessory
onClearTapped={() => {
setImportText('');
}}
@ -185,7 +215,7 @@ const WalletsImport = () => {
/>
),
android: isToolbarVisibleForAndroid && (
<BlueDoneAndDismissKeyboardInputAccessory
<DoneAndDismissKeyboardInputAccessory
onClearTapped={() => {
setImportText('');
Keyboard.dismiss();
@ -197,7 +227,7 @@ const WalletsImport = () => {
/>
),
})}
</SafeArea>
</ScrollView>
);
};

View File

@ -4,12 +4,16 @@ import { ActivityIndicator, Keyboard, LayoutAnimation, Platform, ScrollView, Sty
import { Icon } from '@rneui/themed';
import Share from 'react-native-share';
import triggerHapticFeedback, { HapticFeedbackTypes } from '../../blue_modules/hapticFeedback';
import { BlueDoneAndDismissKeyboardInputAccessory, BlueFormLabel, BlueSpacing10, BlueSpacing20, BlueSpacing40 } from '../../BlueComponents';
import { BlueFormLabel, BlueSpacing10, BlueSpacing20, BlueSpacing40 } from '../../BlueComponents';
import presentAlert from '../../components/Alert';
import { FButton, FContainer } from '../../components/FloatButtons';
import { useTheme } from '../../components/themes';
import loc from '../../loc';
import { useStorage } from '../../hooks/context/useStorage';
import {
DoneAndDismissKeyboardInputAccessory,
DoneAndDismissKeyboardInputAccessoryViewID,
} from '../../components/DoneAndDismissKeyboardInputAccessory';
const SignVerify = () => {
const { colors } = useTheme();
@ -161,7 +165,7 @@ const SignVerify = () => {
value={message}
onChangeText={setMessage}
testID="Message"
inputAccessoryViewID={BlueDoneAndDismissKeyboardInputAccessory.InputAccessoryViewID}
inputAccessoryViewID={DoneAndDismissKeyboardInputAccessoryViewID}
style={[styles.flex, styles.text, styles.textMessage, stylesHooks.text]}
autoCorrect={false}
autoCapitalize="none"
@ -201,7 +205,7 @@ const SignVerify = () => {
{Platform.select({
ios: (
<BlueDoneAndDismissKeyboardInputAccessory
<DoneAndDismissKeyboardInputAccessory
onClearTapped={() => setMessage('')}
onPasteTapped={text => {
setMessage(text);
@ -210,7 +214,7 @@ const SignVerify = () => {
/>
),
android: isToolbarVisibleForAndroid && (
<BlueDoneAndDismissKeyboardInputAccessory
<DoneAndDismissKeyboardInputAccessory
onClearTapped={() => {
setMessage('');
Keyboard.dismiss();

View File

@ -18,7 +18,7 @@
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()}>
+ return (!this.isCaptureRetakeMode() && (<TouchableOpacity style={{ backgroundColor: '#FFFFFF', borderRadius: 20, height: 40, marginHorizontal: 15 }} 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>));
}

View File

@ -1,17 +1,7 @@
import assert from 'assert';
import * as bitcoin from 'bitcoinjs-lib';
import {
expectToBeVisible,
extractTextFromElementById,
hashIt,
helperCreateWallet,
helperDeleteWallet,
helperSwitchAdvancedMode,
sleep,
sup,
yo,
} from './helperz';
import { expectToBeVisible, extractTextFromElementById, hashIt, helperCreateWallet, helperDeleteWallet, sleep, sup, yo } from './helperz';
import { element } from 'detox';
/**
@ -64,14 +54,8 @@ describe('BlueWallet UI Tests - no wallets', () => {
await element(by.id('QuickActionsSwitch')).tap();
await element(by.id('QuickActionsSwitch')).tap();
await device.pressBack();
await device.pressBack();
// enable AdvancedMode
await element(by.id('AdvancedMode')).tap();
await device.pressBack();
// disable it:
await element(by.id('GeneralSettings')).tap();
await element(by.id('AdvancedMode')).tap();
await device.pressBack();
//
// currency
// change currency to ARS ($) and switch it back to USD ($)
@ -472,7 +456,6 @@ describe('BlueWallet UI Tests - no wallets', () => {
if (require('fs').existsSync(lockFile)) return console.warn('skipping as it previously passed on Travis');
}
await device.launchApp({ delete: true }); // reinstalling the app just for any case to clean up app's storage
await helperSwitchAdvancedMode();
await yo('WalletsList');
await element(by.id('WalletsList')).swipe('left', 'fast', 1); // in case emu screen is small and it doesnt fit
await sleep(200); // Wait until bounce animation finishes.
@ -542,7 +525,6 @@ describe('BlueWallet UI Tests - no wallets', () => {
await device.pressBack();
await helperDeleteWallet('Multisig Vault');
await helperSwitchAdvancedMode(); // turn off advanced mode
process.env.TRAVIS && require('fs').writeFileSync(lockFile, '1');
});
@ -686,9 +668,6 @@ describe('BlueWallet UI Tests - no wallets', () => {
await device.launchApp({ delete: true }); // reinstalling the app just for any case to clean up app's storage
await yo('WalletsList');
// enable AdvancedMode to see derivation path in wallet details
await helperSwitchAdvancedMode();
await element(by.id('WalletsList')).swipe('left', 'fast', 1); // in case emu screen is small and it doesnt fit
await sleep(200); // Wait until bounce animation finishes.
// going to Import Wallet screen and importing mnemonic
@ -698,8 +677,10 @@ describe('BlueWallet UI Tests - no wallets', () => {
await element(by.id('MnemonicInput')).replaceText(
'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about',
);
await element(by.id('AskPassphrase')).tap();
await element(by.id('SearchAccounts')).tap();
await element(by.id('HeaderRightButton')).tap();
await element(by.text('Passphrase')).tap();
await element(by.id('HeaderRightButton')).tap();
await element(by.text('Search accounts')).tap();
await element(by.id('DoImport')).tap();
await sleep(1000);
@ -734,7 +715,6 @@ describe('BlueWallet UI Tests - no wallets', () => {
await device.pressBack();
await device.pressBack();
await helperDeleteWallet('Imported HD Legacy (BIP44 P2PKH)');
await helperSwitchAdvancedMode();
process.env.TRAVIS && require('fs').writeFileSync(lockFile, '1');
});

View File

@ -382,9 +382,9 @@ describe('BlueWallet UI Tests - import BIP84 wallet', () => {
if (!(await getSwitchValue('BIP47Switch'))) {
await expect(element(by.text('Contacts'))).not.toBeVisible();
await element(by.id('BIP47Switch')).tap();
await element(by.id('WalletDetailsScroll')).swipe('up', 'fast', 1);
await expect(element(by.text('Contacts'))).toBeVisible();
await element(by.text('Save')).tap(); // automatically goes back 1 screen
await element(by.text('OK')).tap();
await device.pressBack();
} else {
await device.pressBack();
}
@ -504,18 +504,16 @@ describe('BlueWallet UI Tests - import BIP84 wallet', () => {
await element(by.id('WalletDetails')).tap();
// rename test
await element(by.id('WalletNameInput')).replaceText('testname\n');
await element(by.id('Save')).tap();
await sup('OK');
await element(by.text('OK')).tap();
await element(by.id('WalletNameInput')).replaceText('testname');
await device.pressBack();
await sup('testname');
await expect(element(by.id('WalletLabel'))).toHaveText('testname');
await element(by.id('WalletDetails')).tap();
// rename back
await element(by.id('WalletNameInput')).replaceText('Imported HD SegWit (BIP84 Bech32 Native)\n');
await element(by.id('Save')).tap();
await sup('OK');
await element(by.text('OK')).tap();
await element(by.id('WalletNameInput')).replaceText('Imported HD SegWit (BIP84 Bech32 Native)');
await device.pressBack();
await sup('Imported HD SegWit (BIP84 Bech32 Native)');
await expect(element(by.id('WalletLabel'))).toHaveText('Imported HD SegWit (BIP84 Bech32 Native)');
await element(by.id('WalletDetails')).tap();

View File

@ -142,11 +142,3 @@ export async function helperCreateWallet(walletName) {
await element(by.id('WalletsList')).swipe('right', 'fast', 1); // in case emu screen is small and it doesnt fit
await expect(element(by.id(walletName || 'cr34t3d'))).toBeVisible();
}
export async function helperSwitchAdvancedMode() {
await element(by.id('SettingsButton')).tap();
await element(by.id('GeneralSettings')).tap();
await element(by.id('AdvancedMode')).tap();
await device.pressBack();
await device.pressBack();
}

View File

@ -7,10 +7,18 @@ const keys = {
OpenInBlockExplorer: 'open_in_blockExplorer',
CopyAmount: 'copyAmount',
CopyNote: 'copyNote',
ManageWallets: 'manageWallets',
ImportWallet: 'importWallet',
HideBalance: 'hideBalance',
ViewInBitcoin: 'viewInBitcoin',
ViewInSats: 'viewInSats',
ViewInFiat: 'viewInFiat',
Entropy: 'entropy',
SearchAccount: 'searchAccount',
Passphrase: 'passphrase',
MoreInfo: 'moreInfo',
SaveChanges: 'saveChanges',
PaymentsCode: 'paymentsCode',
};
const icons = {
@ -29,12 +37,36 @@ const icons = {
Note: {
iconValue: 'note.text',
},
ManageWallets: {
iconValue: 'slider.horizontal.3',
},
ImportWallet: {
iconValue: 'square.and.arrow.down.on.square',
},
ViewInBitcoin: {
iconValue: 'bitcoinsign.circle',
},
ViewInFiat: {
iconValue: 'coloncurrencysign.circle',
},
Entropy: {
iconValue: 'dice',
},
SearchAccount: {
iconValue: 'magnifyingglass',
},
Passphrase: {
iconValue: 'rectangle.and.pencil.and.ellipsis',
},
MoreInfo: {
iconValue: 'info.circle',
},
SaveChanges: {
iconValue: 'checkmark',
},
PaymentsCode: {
iconValue: 'qrcode',
},
};
export const CommonToolTipActions = {
@ -68,6 +100,16 @@ export const CommonToolTipActions = {
text: loc.transactions.details_copy_note,
icon: icons.Clipboard,
},
ManageWallet: {
id: keys.ManageWallets,
text: loc.wallets.manage_title,
icon: icons.ManageWallets,
},
ImportWallet: {
id: keys.ImportWallet,
text: loc.wallets.add_import_wallet,
icon: icons.ImportWallet,
},
HideBalance: {
id: keys.HideBalance,
text: loc.transactions.details_balance_hide,
@ -78,7 +120,6 @@ export const CommonToolTipActions = {
text: loc.total_balance_view.view_in_fiat,
icon: icons.ViewInFiat,
},
ViewInSats: {
id: keys.ViewInSats,
text: loc.total_balance_view.view_in_sats,
@ -89,4 +130,38 @@ export const CommonToolTipActions = {
text: loc.total_balance_view.view_in_bitcoin,
icon: icons.ViewInBitcoin,
},
Entropy: {
id: keys.Entropy,
text: loc.wallets.add_entropy_provide,
icon: icons.Entropy,
},
SearchAccount: {
id: keys.SearchAccount,
text: loc.wallets.import_search_accounts,
icon: icons.SearchAccount,
menuState: false,
},
Passphrase: {
id: keys.Passphrase,
text: loc.wallets.import_passphrase,
icon: icons.Passphrase,
menuState: false,
},
MoreInfo: {
id: keys.MoreInfo,
text: loc.wallets.more_info,
icon: icons.MoreInfo,
hidden: false,
},
SaveChanges: {
id: keys.SaveChanges,
text: loc._.save,
icon: icons.SaveChanges,
},
PaymentCode: {
id: keys.PaymentsCode,
text: loc.bip47.purpose,
icon: icons.PaymentsCode,
menuState: false,
},
};