mirror of
https://github.com/BlueWallet/BlueWallet.git
synced 2025-02-22 15:04:50 +01:00
REF: Add Wallet advanced options (#7023)
This commit is contained in:
parent
4bc7e53a6e
commit
fdfb6d11cf
23 changed files with 586 additions and 454 deletions
|
@ -134,11 +134,11 @@ jobs:
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: BlueWallet.${{env.PROJECT_VERSION}}(${{env.NEW_BUILD_NUMBER}}).ipa
|
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:
|
testflight-upload:
|
||||||
needs: build
|
needs: build
|
||||||
runs-on: macos-14
|
runs-on: macos-latest
|
||||||
if: github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'testflight')
|
if: github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'testflight')
|
||||||
env:
|
env:
|
||||||
APPLE_ID: ${{ secrets.APPLE_ID }}
|
APPLE_ID: ${{ secrets.APPLE_ID }}
|
||||||
|
@ -168,12 +168,12 @@ jobs:
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: BlueWallet.${{ needs.build.outputs.project_version }}(${{ needs.build.outputs.new_build_number }}).ipa
|
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
|
- 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
|
- name: Upload to TestFlight
|
||||||
env:
|
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 }}
|
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
|
||||||
GIT_ACCESS_TOKEN: ${{ secrets.GIT_ACCESS_TOKEN }}
|
GIT_ACCESS_TOKEN: ${{ secrets.GIT_ACCESS_TOKEN }}
|
||||||
GIT_URL: ${{ secrets.GIT_URL }}
|
GIT_URL: ${{ secrets.GIT_URL }}
|
||||||
|
|
|
@ -67,13 +67,12 @@ const isReactNative = typeof navigator !== 'undefined' && navigator?.product ===
|
||||||
export class BlueApp {
|
export class BlueApp {
|
||||||
static FLAG_ENCRYPTED = 'data_encrypted';
|
static FLAG_ENCRYPTED = 'data_encrypted';
|
||||||
static LNDHUB = 'lndhub';
|
static LNDHUB = 'lndhub';
|
||||||
static ADVANCED_MODE_ENABLED = 'advancedmodeenabled';
|
|
||||||
static DO_NOT_TRACK = 'donottrack';
|
static DO_NOT_TRACK = 'donottrack';
|
||||||
static HANDOFF_STORAGE_KEY = 'HandOff';
|
static HANDOFF_STORAGE_KEY = 'HandOff';
|
||||||
|
|
||||||
private static _instance: BlueApp | null = null;
|
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 cachedPassword?: false | string;
|
||||||
public tx_metadata: TTXMetadata;
|
public tx_metadata: TTXMetadata;
|
||||||
|
@ -882,17 +881,6 @@ export class BlueApp {
|
||||||
return finalBalance;
|
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> => {
|
isHandoffEnabled = async (): Promise<boolean> => {
|
||||||
try {
|
try {
|
||||||
return !!(await AsyncStorage.getItem(BlueApp.HANDOFF_STORAGE_KEY));
|
return !!(await AsyncStorage.getItem(BlueApp.HANDOFF_STORAGE_KEY));
|
||||||
|
|
|
@ -69,8 +69,6 @@ interface SettingsContextType {
|
||||||
setIsHandOffUseEnabledAsyncStorage: (value: boolean) => Promise<void>;
|
setIsHandOffUseEnabledAsyncStorage: (value: boolean) => Promise<void>;
|
||||||
isPrivacyBlurEnabled: boolean;
|
isPrivacyBlurEnabled: boolean;
|
||||||
setIsPrivacyBlurEnabledState: (value: boolean) => void;
|
setIsPrivacyBlurEnabledState: (value: boolean) => void;
|
||||||
isAdvancedModeEnabled: boolean;
|
|
||||||
setIsAdvancedModeEnabledStorage: (value: boolean) => Promise<void>;
|
|
||||||
isDoNotTrackEnabled: boolean;
|
isDoNotTrackEnabled: boolean;
|
||||||
setDoNotTrackStorage: (value: boolean) => Promise<void>;
|
setDoNotTrackStorage: (value: boolean) => Promise<void>;
|
||||||
isWidgetBalanceDisplayAllowed: boolean;
|
isWidgetBalanceDisplayAllowed: boolean;
|
||||||
|
@ -96,8 +94,6 @@ const defaultSettingsContext: SettingsContextType = {
|
||||||
setIsHandOffUseEnabledAsyncStorage: async () => {},
|
setIsHandOffUseEnabledAsyncStorage: async () => {},
|
||||||
isPrivacyBlurEnabled: true,
|
isPrivacyBlurEnabled: true,
|
||||||
setIsPrivacyBlurEnabledState: () => {},
|
setIsPrivacyBlurEnabledState: () => {},
|
||||||
isAdvancedModeEnabled: false,
|
|
||||||
setIsAdvancedModeEnabledStorage: async () => {},
|
|
||||||
isDoNotTrackEnabled: false,
|
isDoNotTrackEnabled: false,
|
||||||
setDoNotTrackStorage: async () => {},
|
setDoNotTrackStorage: async () => {},
|
||||||
isWidgetBalanceDisplayAllowed: true,
|
isWidgetBalanceDisplayAllowed: true,
|
||||||
|
@ -125,8 +121,6 @@ export const SettingsProvider: React.FC<{ children: React.ReactNode }> = ({ chil
|
||||||
const [isHandOffUseEnabled, setHandOffUseEnabled] = useState<boolean>(false);
|
const [isHandOffUseEnabled, setHandOffUseEnabled] = useState<boolean>(false);
|
||||||
// PrivacyBlur
|
// PrivacyBlur
|
||||||
const [isPrivacyBlurEnabled, setIsPrivacyBlurEnabled] = useState<boolean>(true);
|
const [isPrivacyBlurEnabled, setIsPrivacyBlurEnabled] = useState<boolean>(true);
|
||||||
// AdvancedMode
|
|
||||||
const [isAdvancedModeEnabled, setIsAdvancedModeEnabled] = useState<boolean>(false);
|
|
||||||
// DoNotTrack
|
// DoNotTrack
|
||||||
const [isDoNotTrackEnabled, setIsDoNotTrackEnabled] = useState<boolean>(false);
|
const [isDoNotTrackEnabled, setIsDoNotTrackEnabled] = useState<boolean>(false);
|
||||||
// WidgetCommunication
|
// WidgetCommunication
|
||||||
|
@ -141,19 +135,10 @@ export const SettingsProvider: React.FC<{ children: React.ReactNode }> = ({ chil
|
||||||
const [isTotalBalanceEnabled, setIsTotalBalanceEnabled] = useState<boolean>(true);
|
const [isTotalBalanceEnabled, setIsTotalBalanceEnabled] = useState<boolean>(true);
|
||||||
const [totalBalancePreferredUnit, setTotalBalancePreferredUnitState] = useState<BitcoinUnit>(BitcoinUnit.BTC);
|
const [totalBalancePreferredUnit, setTotalBalancePreferredUnitState] = useState<BitcoinUnit>(BitcoinUnit.BTC);
|
||||||
|
|
||||||
const advancedModeStorage = useAsyncStorage(BlueApp.ADVANCED_MODE_ENABLED);
|
|
||||||
const languageStorage = useAsyncStorage(STORAGE_KEY);
|
const languageStorage = useAsyncStorage(STORAGE_KEY);
|
||||||
const { walletsInitialized } = useStorage();
|
const { walletsInitialized } = useStorage();
|
||||||
|
|
||||||
useEffect(() => {
|
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()
|
getIsHandOffUseEnabled()
|
||||||
.then(handOff => {
|
.then(handOff => {
|
||||||
console.debug('SettingsContext handOff:', handOff);
|
console.debug('SettingsContext handOff:', handOff);
|
||||||
|
@ -243,14 +228,6 @@ export const SettingsProvider: React.FC<{ children: React.ReactNode }> = ({ chil
|
||||||
setLanguage(newLanguage);
|
setLanguage(newLanguage);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const setIsAdvancedModeEnabledStorage = useCallback(
|
|
||||||
async (value: boolean) => {
|
|
||||||
await advancedModeStorage.setItem(JSON.stringify(value));
|
|
||||||
setIsAdvancedModeEnabled(value);
|
|
||||||
},
|
|
||||||
[advancedModeStorage],
|
|
||||||
);
|
|
||||||
|
|
||||||
const setDoNotTrackStorage = useCallback(async (value: boolean) => {
|
const setDoNotTrackStorage = useCallback(async (value: boolean) => {
|
||||||
await DefaultPreference.setName(GROUP_IO_BLUEWALLET);
|
await DefaultPreference.setName(GROUP_IO_BLUEWALLET);
|
||||||
if (value) {
|
if (value) {
|
||||||
|
@ -321,8 +298,6 @@ export const SettingsProvider: React.FC<{ children: React.ReactNode }> = ({ chil
|
||||||
setIsHandOffUseEnabledAsyncStorage,
|
setIsHandOffUseEnabledAsyncStorage,
|
||||||
isPrivacyBlurEnabled,
|
isPrivacyBlurEnabled,
|
||||||
setIsPrivacyBlurEnabledState,
|
setIsPrivacyBlurEnabledState,
|
||||||
isAdvancedModeEnabled,
|
|
||||||
setIsAdvancedModeEnabledStorage,
|
|
||||||
isDoNotTrackEnabled,
|
isDoNotTrackEnabled,
|
||||||
setDoNotTrackStorage,
|
setDoNotTrackStorage,
|
||||||
isWidgetBalanceDisplayAllowed,
|
isWidgetBalanceDisplayAllowed,
|
||||||
|
@ -347,8 +322,6 @@ export const SettingsProvider: React.FC<{ children: React.ReactNode }> = ({ chil
|
||||||
setIsHandOffUseEnabledAsyncStorage,
|
setIsHandOffUseEnabledAsyncStorage,
|
||||||
isPrivacyBlurEnabled,
|
isPrivacyBlurEnabled,
|
||||||
setIsPrivacyBlurEnabledState,
|
setIsPrivacyBlurEnabledState,
|
||||||
isAdvancedModeEnabled,
|
|
||||||
setIsAdvancedModeEnabledStorage,
|
|
||||||
isDoNotTrackEnabled,
|
isDoNotTrackEnabled,
|
||||||
setDoNotTrackStorage,
|
setDoNotTrackStorage,
|
||||||
isWidgetBalanceDisplayAllowed,
|
isWidgetBalanceDisplayAllowed,
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import React, { Ref, useCallback, useMemo } from 'react';
|
import React, { Ref, useCallback, useMemo } from 'react';
|
||||||
import { Platform, Pressable, TouchableOpacity } from 'react-native';
|
import { Platform, Pressable, TouchableOpacity } from 'react-native';
|
||||||
|
import { MenuView, MenuAction, NativeActionEvent } from '@react-native-menu/menu';
|
||||||
import {
|
import {
|
||||||
ContextMenuView,
|
ContextMenuView,
|
||||||
RenderItem,
|
RenderItem,
|
||||||
|
@ -8,7 +9,6 @@ import {
|
||||||
IconConfig,
|
IconConfig,
|
||||||
MenuElementConfig,
|
MenuElementConfig,
|
||||||
} from 'react-native-ios-context-menu';
|
} from 'react-native-ios-context-menu';
|
||||||
import { MenuView, MenuAction, NativeActionEvent } from '@react-native-menu/menu';
|
|
||||||
import { ToolTipMenuProps, Action } from './types';
|
import { ToolTipMenuProps, Action } from './types';
|
||||||
import { useSettings } from '../hooks/context/useSettings';
|
import { useSettings } from '../hooks/context/useSettings';
|
||||||
|
|
||||||
|
@ -30,6 +30,7 @@ const ToolTipMenu = React.memo((props: ToolTipMenuProps, ref?: Ref<any>) => {
|
||||||
|
|
||||||
const { language } = useSettings();
|
const { language } = useSettings();
|
||||||
|
|
||||||
|
// Map Menu Items for iOS Context Menu
|
||||||
const mapMenuItemForContextMenuView = useCallback((action: Action) => {
|
const mapMenuItemForContextMenuView = useCallback((action: Action) => {
|
||||||
if (!action.id) return null;
|
if (!action.id) return null;
|
||||||
return {
|
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 => {
|
const mapMenuItemForMenuView = useCallback((action: Action): MenuAction | null => {
|
||||||
if (!action.id) return 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 {
|
return {
|
||||||
id: action.id.toString(),
|
id: action.id.toString(),
|
||||||
title: action.text,
|
title: action.text,
|
||||||
|
subtitle: action.subtitle,
|
||||||
image: action.icon?.iconValue ? action.icon.iconValue : undefined,
|
image: action.icon?.iconValue ? action.icon.iconValue : undefined,
|
||||||
state: action.menuState === undefined ? undefined : ((action.menuState ? 'on' : 'off') as MenuState),
|
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 = () => {
|
const renderContextMenuView = () => {
|
||||||
console.debug('ToolTipMenu.tsx rendering: renderContextMenuView');
|
|
||||||
return (
|
return (
|
||||||
<ContextMenuView
|
<ContextMenuView
|
||||||
lazyPreview
|
lazyPreview
|
||||||
|
@ -139,7 +155,6 @@ const ToolTipMenu = React.memo((props: ToolTipMenuProps, ref?: Ref<any>) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const renderMenuView = () => {
|
const renderMenuView = () => {
|
||||||
console.debug('ToolTipMenu.tsx rendering: renderMenuView');
|
|
||||||
return (
|
return (
|
||||||
<MenuView
|
<MenuView
|
||||||
title={title}
|
title={title}
|
||||||
|
@ -147,7 +162,7 @@ const ToolTipMenu = React.memo((props: ToolTipMenuProps, ref?: Ref<any>) => {
|
||||||
onPressAction={handlePressMenuItemForMenuView}
|
onPressAction={handlePressMenuItemForMenuView}
|
||||||
actions={Platform.OS === 'ios' ? menuViewItemsIOS : menuViewItemsAndroid}
|
actions={Platform.OS === 'ios' ? menuViewItemsIOS : menuViewItemsAndroid}
|
||||||
shouldOpenOnLongPress={!isMenuPrimaryAction}
|
shouldOpenOnLongPress={!isMenuPrimaryAction}
|
||||||
// @ts-ignore: its not in the types but it works
|
// @ts-ignore: Not exposed in types
|
||||||
accessibilityLabel={props.accessibilityLabel}
|
accessibilityLabel={props.accessibilityLabel}
|
||||||
accessibilityHint={props.accessibilityHint}
|
accessibilityHint={props.accessibilityHint}
|
||||||
accessibilityRole={props.accessibilityRole}
|
accessibilityRole={props.accessibilityRole}
|
||||||
|
|
|
@ -289,7 +289,7 @@ export const TransactionListItem: React.FC<TransactionListItemProps> = React.mem
|
||||||
handleOnViewOnBlockExplorer,
|
handleOnViewOnBlockExplorer,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
const toolTipActions = useMemo((): Action[] | Action[][] => {
|
const toolTipActions = useMemo((): Action[] => {
|
||||||
const actions: (Action | Action[])[] = [];
|
const actions: (Action | Action[])[] = [];
|
||||||
|
|
||||||
if (rowTitle !== loc.lnd.expired) {
|
if (rowTitle !== loc.lnd.expired) {
|
||||||
|
@ -308,7 +308,7 @@ export const TransactionListItem: React.FC<TransactionListItemProps> = React.mem
|
||||||
actions.push([CommonToolTipActions.ExpandNote]);
|
actions.push([CommonToolTipActions.ExpandNote]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return actions as Action[] | Action[][];
|
return actions as Action[];
|
||||||
}, [item.hash, subtitle, rowTitle, subtitleNumberOfLines]);
|
}, [item.hash, subtitle, rowTitle, subtitleNumberOfLines]);
|
||||||
|
|
||||||
const accessibilityState = useMemo(() => {
|
const accessibilityState = useMemo(() => {
|
||||||
|
|
|
@ -209,7 +209,7 @@ const styles = StyleSheet.create({
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const getAvailableActions = ({ allowSignVerifyMessage }: { allowSignVerifyMessage: boolean }): Action[] | Action[][] => {
|
const getAvailableActions = ({ allowSignVerifyMessage }: { allowSignVerifyMessage: boolean }): Action[] => {
|
||||||
const actions = [
|
const actions = [
|
||||||
{
|
{
|
||||||
id: actionKeys.CopyToClipboard,
|
id: actionKeys.CopyToClipboard,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { AccessibilityRole, ViewStyle } from 'react-native';
|
import { AccessibilityRole, ViewStyle, ColorValue } from 'react-native';
|
||||||
|
|
||||||
export interface Action {
|
export interface Action {
|
||||||
id: string | number;
|
id: string | number;
|
||||||
|
@ -7,13 +7,19 @@ export interface Action {
|
||||||
iconValue: string;
|
iconValue: string;
|
||||||
};
|
};
|
||||||
menuTitle?: string;
|
menuTitle?: string;
|
||||||
|
subtitle?: string;
|
||||||
menuState?: 'mixed' | boolean | undefined;
|
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;
|
disabled?: boolean;
|
||||||
displayInline?: boolean;
|
subactions?: Action[]; // Nested/Inline actions (subactions) within an action
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ToolTipMenuProps {
|
export interface ToolTipMenuProps {
|
||||||
actions: Action[] | Action[][];
|
actions: Action[];
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
enableAndroidRipple?: boolean;
|
enableAndroidRipple?: boolean;
|
||||||
dismissMenu?: () => void;
|
dismissMenu?: () => void;
|
||||||
|
|
|
@ -167,7 +167,8 @@ platform :ios do
|
||||||
type: "development",
|
type: "development",
|
||||||
app_identifier: app_identifier,
|
app_identifier: app_identifier,
|
||||||
readonly: false, # This will regenerate the provisioning profile if needed
|
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
|
end
|
||||||
|
|
||||||
|
@ -211,6 +212,7 @@ platform :ios do
|
||||||
git_basic_authorization: ENV["GIT_ACCESS_TOKEN"],
|
git_basic_authorization: ENV["GIT_ACCESS_TOKEN"],
|
||||||
git_url: ENV["GIT_URL"],
|
git_url: ENV["GIT_URL"],
|
||||||
type: "appstore",
|
type: "appstore",
|
||||||
|
clone_branch_directly: true, # Skip if the branch already exists (Exit 128 error)
|
||||||
platform: platform,
|
platform: platform,
|
||||||
app_identifier: app_identifier,
|
app_identifier: app_identifier,
|
||||||
team_id: ENV["ITC_TEAM_ID"],
|
team_id: ENV["ITC_TEAM_ID"],
|
||||||
|
@ -228,7 +230,8 @@ platform :ios do
|
||||||
type: "development",
|
type: "development",
|
||||||
platform: "catalyst",
|
platform: "catalyst",
|
||||||
app_identifier: app_identifiers,
|
app_identifier: app_identifiers,
|
||||||
readonly: true
|
readonly: true,
|
||||||
|
clone_branch_directly: true
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -238,7 +241,9 @@ platform :ios do
|
||||||
type: "appstore",
|
type: "appstore",
|
||||||
platform: "catalyst",
|
platform: "catalyst",
|
||||||
app_identifier: app_identifiers,
|
app_identifier: app_identifiers,
|
||||||
readonly: true
|
readonly: true,
|
||||||
|
clone_branch_directly: true
|
||||||
|
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -250,14 +255,16 @@ platform :ios do
|
||||||
platform: "catalyst",
|
platform: "catalyst",
|
||||||
app_identifier: app_identifier,
|
app_identifier: app_identifier,
|
||||||
readonly: false,
|
readonly: false,
|
||||||
force_for_new_devices: true
|
force_for_new_devices: true,
|
||||||
|
clone_branch_directly: true
|
||||||
)
|
)
|
||||||
|
|
||||||
match(
|
match(
|
||||||
type: "appstore",
|
type: "appstore",
|
||||||
platform: "catalyst",
|
platform: "catalyst",
|
||||||
app_identifier: app_identifier,
|
app_identifier: app_identifier,
|
||||||
readonly: false
|
readonly: false,
|
||||||
|
clone_branch_directly: true
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -326,8 +333,8 @@ platform :ios do
|
||||||
changelog = ENV["LATEST_COMMIT_MESSAGE"]
|
changelog = ENV["LATEST_COMMIT_MESSAGE"]
|
||||||
|
|
||||||
upload_to_testflight(
|
upload_to_testflight(
|
||||||
api_key_path: "appstore_api_key.json",
|
api_key_path: "./appstore_api_key.json",
|
||||||
ipa: "./build/BlueWallet.#{ENV['PROJECT_VERSION']}(#{ENV['NEW_BUILD_NUMBER']}).ipa",
|
ipa: "./BlueWallet.#{ENV['PROJECT_VERSION']}(#{ENV['NEW_BUILD_NUMBER']}).ipa",
|
||||||
skip_waiting_for_build_processing: true, # Do not wait for processing
|
skip_waiting_for_build_processing: true, # Do not wait for processing
|
||||||
changelog: changelog
|
changelog: changelog
|
||||||
)
|
)
|
||||||
|
|
|
@ -219,7 +219,6 @@
|
||||||
"about_sm_twitter": "Follow us on Twitter",
|
"about_sm_twitter": "Follow us on Twitter",
|
||||||
"privacy_temporary_screenshots": "Allow Screenshots",
|
"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.",
|
"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": "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.",
|
"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.",
|
"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.",
|
||||||
|
@ -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.",
|
"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.",
|
"biometrics_fail": "If {type} is not enabled, or fails to unlock, you can use your device passcode as an alternative.",
|
||||||
"general": "General",
|
"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": "Continuity",
|
||||||
"general_continuity_e": "When enabled, you will be able to view selected wallets, and transactions, using your other Apple iCloud connected devices.",
|
"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 BlueWallet’s infrastructure. Leave blank to use GroundControl’s default server.",
|
"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 BlueWallet’s infrastructure. Leave blank to use GroundControl’s default server.",
|
||||||
|
@ -479,7 +476,8 @@
|
||||||
"add_ln_wallet_first": "You must first add a Lightning wallet.",
|
"add_ln_wallet_first": "You must first add a Lightning wallet.",
|
||||||
"identity_pubkey": "Identity Pubkey",
|
"identity_pubkey": "Identity Pubkey",
|
||||||
"xpub_title": "Wallet XPUB",
|
"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": {
|
"total_balance_view": {
|
||||||
"view_in_bitcoin": "View in Bitcoin",
|
"view_in_bitcoin": "View in Bitcoin",
|
||||||
|
@ -489,7 +487,7 @@
|
||||||
"explanation": "View the total balance of all your wallets in the overview screen."
|
"explanation": "View the total balance of all your wallets in the overview screen."
|
||||||
},
|
},
|
||||||
"multisig": {
|
"multisig": {
|
||||||
"multisig_vault": "Vault",
|
"multisig_vault": "Multisig Vault",
|
||||||
"default_label": "Multisig Vault",
|
"default_label": "Multisig Vault",
|
||||||
"multisig_vault_explain": "Best security for large amounts",
|
"multisig_vault_explain": "Best security for large amounts",
|
||||||
"provide_signature": "Provide signature",
|
"provide_signature": "Provide signature",
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { createNativeStackNavigator } from '@react-navigation/native-stack';
|
import { createNativeStackNavigator } from '@react-navigation/native-stack';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import navigationStyle from '../components/navigationStyle';
|
import navigationStyle, { CloseButtonPosition } from '../components/navigationStyle';
|
||||||
import { useTheme } from '../components/themes';
|
import { useTheme } from '../components/themes';
|
||||||
import loc from '../loc';
|
import loc from '../loc';
|
||||||
import {
|
import {
|
||||||
|
@ -49,7 +49,7 @@ const AddWalletStack = () => {
|
||||||
name="AddWallet"
|
name="AddWallet"
|
||||||
component={AddComponent}
|
component={AddComponent}
|
||||||
options={navigationStyle({
|
options={navigationStyle({
|
||||||
headerBackVisible: false,
|
closeButtonPosition: CloseButtonPosition.Left,
|
||||||
title: loc.wallets.add_title,
|
title: loc.wallets.add_title,
|
||||||
})(theme)}
|
})(theme)}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -73,7 +73,6 @@ const DetailViewStackScreensStack = () => {
|
||||||
const { wallets } = useStorage();
|
const { wallets } = useStorage();
|
||||||
const { isTotalBalanceEnabled } = useSettings();
|
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 DetailButton = useMemo(() => <HeaderRightButton testID="DetailButton" disabled={true} title={loc.send.create_details} />, []);
|
||||||
|
|
||||||
const navigateToAddWallet = useCallback(() => {
|
const navigateToAddWallet = useCallback(() => {
|
||||||
|
@ -122,7 +121,6 @@ const DetailViewStackScreensStack = () => {
|
||||||
options={navigationStyle({
|
options={navigationStyle({
|
||||||
headerTitle: loc.wallets.details_title,
|
headerTitle: loc.wallets.details_title,
|
||||||
statusBarStyle: 'auto',
|
statusBarStyle: 'auto',
|
||||||
headerRight: () => SaveButton,
|
|
||||||
})(theme)}
|
})(theme)}
|
||||||
/>
|
/>
|
||||||
<DetailViewStack.Screen
|
<DetailViewStack.Screen
|
||||||
|
@ -247,7 +245,11 @@ const DetailViewStackScreensStack = () => {
|
||||||
options={navigationStyle({ title: loc.addresses.addresses_title, statusBarStyle: 'auto' })(theme)}
|
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="SendDetailsRoot" component={SendDetailsStack} options={NavigationDefaultOptions} />
|
||||||
<DetailViewStack.Screen name="LNDCreateInvoiceRoot" component={LNDCreateInvoiceRoot} options={NavigationDefaultOptions} />
|
<DetailViewStack.Screen name="LNDCreateInvoiceRoot" component={LNDCreateInvoiceRoot} options={NavigationDefaultOptions} />
|
||||||
<DetailViewStack.Screen name="ScanLndInvoiceRoot" component={ScanLndInvoiceRoot} options={NavigationDefaultOptions} />
|
<DetailViewStack.Screen name="ScanLndInvoiceRoot" component={ScanLndInvoiceRoot} options={NavigationDefaultOptions} />
|
||||||
|
|
|
@ -1,6 +1,17 @@
|
||||||
import { useFocusEffect, useRoute } from '@react-navigation/native';
|
import { useFocusEffect, useRoute } from '@react-navigation/native';
|
||||||
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import { BackHandler, InteractionManager, ScrollView, StyleSheet, Text, TextInput, View } from 'react-native';
|
import {
|
||||||
|
BackHandler,
|
||||||
|
Image,
|
||||||
|
InteractionManager,
|
||||||
|
LayoutAnimation,
|
||||||
|
ScrollView,
|
||||||
|
StyleSheet,
|
||||||
|
Text,
|
||||||
|
TextInput,
|
||||||
|
TouchableOpacity,
|
||||||
|
View,
|
||||||
|
} from 'react-native';
|
||||||
import Share from 'react-native-share';
|
import Share from 'react-native-share';
|
||||||
|
|
||||||
import * as BlueElectrum from '../../blue_modules/BlueElectrum';
|
import * as BlueElectrum from '../../blue_modules/BlueElectrum';
|
||||||
|
@ -24,6 +35,9 @@ import { SuccessView } from '../send/success';
|
||||||
import { useStorage } from '../../hooks/context/useStorage';
|
import { useStorage } from '../../hooks/context/useStorage';
|
||||||
import { HandOffActivityType } from '../../components/types';
|
import { HandOffActivityType } from '../../components/types';
|
||||||
import SegmentedControl from '../../components/SegmentControl';
|
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];
|
const segmentControlValues = [loc.wallets.details_address, loc.bip47.payment_code];
|
||||||
|
|
||||||
|
@ -43,9 +57,9 @@ const ReceiveDetails = () => {
|
||||||
const [showConfirmedBalance, setShowConfirmedBalance] = useState(false);
|
const [showConfirmedBalance, setShowConfirmedBalance] = useState(false);
|
||||||
const [showAddress, setShowAddress] = useState(false);
|
const [showAddress, setShowAddress] = useState(false);
|
||||||
const [currentTab, setCurrentTab] = useState(segmentControlValues[0]);
|
const [currentTab, setCurrentTab] = useState(segmentControlValues[0]);
|
||||||
const { goBack, setParams } = useExtendedNavigation();
|
const { goBack, setParams, setOptions } = useExtendedNavigation();
|
||||||
const bottomModalRef = useRef(null);
|
const bottomModalRef = useRef(null);
|
||||||
const { colors } = useTheme();
|
const { colors, closeImage } = useTheme();
|
||||||
const [intervalMs, setIntervalMs] = useState(5000);
|
const [intervalMs, setIntervalMs] = useState(5000);
|
||||||
const [eta, setEta] = useState('');
|
const [eta, setEta] = useState('');
|
||||||
const [initialConfirmed, setInitialConfirmed] = useState(0);
|
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(() => {
|
useEffect(() => {
|
||||||
if (showConfirmedBalance) {
|
if (showConfirmedBalance) {
|
||||||
triggerHapticFeedback(HapticFeedbackTypes.NotificationSuccess);
|
triggerHapticFeedback(HapticFeedbackTypes.NotificationSuccess);
|
||||||
}
|
}
|
||||||
}, [showConfirmedBalance]);
|
}, [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
|
// re-fetching address balance periodically
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log('receive/details - useEffect');
|
console.debug('receive/details - useEffect');
|
||||||
|
|
||||||
const intervalId = setInterval(async () => {
|
const intervalId = setInterval(async () => {
|
||||||
try {
|
try {
|
||||||
|
@ -95,9 +213,9 @@ const ReceiveDetails = () => {
|
||||||
const addressToUse = address || decoded.address;
|
const addressToUse = address || decoded.address;
|
||||||
if (!addressToUse) return;
|
if (!addressToUse) return;
|
||||||
|
|
||||||
console.log('checking address', addressToUse, 'for balance...');
|
console.debug('checking address', addressToUse, 'for balance...');
|
||||||
const balance = await BlueElectrum.getBalanceByAddress(addressToUse);
|
const balance = await BlueElectrum.getBalanceByAddress(addressToUse);
|
||||||
console.log('...got', balance);
|
console.debug('...got', balance);
|
||||||
|
|
||||||
if (balance.unconfirmed > 0) {
|
if (balance.unconfirmed > 0) {
|
||||||
if (initialConfirmed === 0 && initialUnconfirmed === 0) {
|
if (initialConfirmed === 0 && initialUnconfirmed === 0) {
|
||||||
|
@ -157,7 +275,7 @@ const ReceiveDetails = () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.debug(error);
|
||||||
}
|
}
|
||||||
}, intervalMs);
|
}, intervalMs);
|
||||||
|
|
||||||
|
@ -209,16 +327,6 @@ const ReceiveDetails = () => {
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
const setAddressBIP21Encoded = useCallback(
|
|
||||||
addr => {
|
|
||||||
const newBip21encoded = DeeplinkSchemaMatch.bip21encode(addr);
|
|
||||||
setParams({ address: addr });
|
|
||||||
setBip21encoded(newBip21encoded);
|
|
||||||
setShowAddress(true);
|
|
||||||
},
|
|
||||||
[setParams],
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
BackHandler.addEventListener('hardwareBackPress', handleBackButton);
|
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(
|
useFocusEffect(
|
||||||
useCallback(() => {
|
useCallback(() => {
|
||||||
const task = InteractionManager.runAfterInteractions(async () => {
|
const task = InteractionManager.runAfterInteractions(async () => {
|
||||||
|
@ -357,7 +427,7 @@ const ReceiveDetails = () => {
|
||||||
|
|
||||||
const handleShareButtonPressed = () => {
|
const handleShareButtonPressed = () => {
|
||||||
Share.open({ message: currentTab === loc.wallets.details_address ? bip21encoded : wallet.getBIP47PaymentCode() }).catch(error =>
|
Share.open({ message: currentTab === loc.wallets.details_address ? bip21encoded : wallet.getBIP47PaymentCode() }).catch(error =>
|
||||||
console.log(error),
|
console.debug(error),
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -16,14 +16,7 @@ const styles = StyleSheet.create({
|
||||||
|
|
||||||
const GeneralSettings: React.FC = () => {
|
const GeneralSettings: React.FC = () => {
|
||||||
const { wallets } = useStorage();
|
const { wallets } = useStorage();
|
||||||
const {
|
const { isHandOffUseEnabled, setIsHandOffUseEnabledAsyncStorage, isLegacyURv1Enabled, setIsLegacyURv1EnabledStorage } = useSettings();
|
||||||
isAdvancedModeEnabled,
|
|
||||||
setIsAdvancedModeEnabledStorage,
|
|
||||||
isHandOffUseEnabled,
|
|
||||||
setIsHandOffUseEnabledAsyncStorage,
|
|
||||||
isLegacyURv1Enabled,
|
|
||||||
setIsLegacyURv1EnabledStorage,
|
|
||||||
} = useSettings();
|
|
||||||
const { navigate } = useNavigation();
|
const { navigate } = useNavigation();
|
||||||
const { colors } = useTheme();
|
const { colors } = useTheme();
|
||||||
|
|
||||||
|
@ -64,14 +57,6 @@ const GeneralSettings: React.FC = () => {
|
||||||
<BlueSpacing20 />
|
<BlueSpacing20 />
|
||||||
</>
|
</>
|
||||||
) : null}
|
) : 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 />
|
<BlueSpacing20 />
|
||||||
<ListItem
|
<ListItem
|
||||||
Component={PressableWrapper}
|
Component={PressableWrapper}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import AsyncStorage from '@react-native-async-storage/async-storage';
|
import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||||
import { useNavigation } from '@react-navigation/native';
|
import { useNavigation } from '@react-navigation/native';
|
||||||
import React, { useEffect, useReducer } from 'react';
|
import React, { useCallback, useEffect, useMemo, useReducer } from 'react';
|
||||||
import {
|
import {
|
||||||
ActivityIndicator,
|
ActivityIndicator,
|
||||||
Alert,
|
Alert,
|
||||||
|
@ -9,7 +9,6 @@ import {
|
||||||
Platform,
|
Platform,
|
||||||
ScrollView,
|
ScrollView,
|
||||||
StyleSheet,
|
StyleSheet,
|
||||||
Text,
|
|
||||||
TextInput,
|
TextInput,
|
||||||
useColorScheme,
|
useColorScheme,
|
||||||
View,
|
View,
|
||||||
|
@ -21,13 +20,15 @@ import { BlueButtonLink, BlueFormLabel, BlueSpacing20, BlueSpacing40, BlueText }
|
||||||
import { BlueApp, HDSegwitBech32Wallet, HDSegwitP2SHWallet, LightningCustodianWallet, SegwitP2SHWallet } from '../../class';
|
import { BlueApp, HDSegwitBech32Wallet, HDSegwitP2SHWallet, LightningCustodianWallet, SegwitP2SHWallet } from '../../class';
|
||||||
import presentAlert from '../../components/Alert';
|
import presentAlert from '../../components/Alert';
|
||||||
import Button from '../../components/Button';
|
import Button from '../../components/Button';
|
||||||
import ListItem from '../../components/ListItem';
|
|
||||||
import { useTheme } from '../../components/themes';
|
import { useTheme } from '../../components/themes';
|
||||||
import WalletButton from '../../components/WalletButton';
|
import WalletButton from '../../components/WalletButton';
|
||||||
import loc from '../../loc';
|
import loc from '../../loc';
|
||||||
import { Chain } from '../../models/bitcoinUnits';
|
import { Chain } from '../../models/bitcoinUnits';
|
||||||
import { useStorage } from '../../hooks/context/useStorage';
|
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 {
|
enum ButtonSelected {
|
||||||
// @ts-ignore: Return later to update
|
// @ts-ignore: Return later to update
|
||||||
|
@ -43,7 +44,6 @@ interface State {
|
||||||
selectedIndex: number;
|
selectedIndex: number;
|
||||||
label: string;
|
label: string;
|
||||||
selectedWalletType: ButtonSelected;
|
selectedWalletType: ButtonSelected;
|
||||||
backdoorPressed: number;
|
|
||||||
entropy: Buffer | undefined;
|
entropy: Buffer | undefined;
|
||||||
entropyButtonText: string;
|
entropyButtonText: string;
|
||||||
}
|
}
|
||||||
|
@ -54,13 +54,12 @@ const ActionTypes = {
|
||||||
SET_SELECTED_INDEX: 'SET_SELECTED_INDEX',
|
SET_SELECTED_INDEX: 'SET_SELECTED_INDEX',
|
||||||
SET_LABEL: 'SET_LABEL',
|
SET_LABEL: 'SET_LABEL',
|
||||||
SET_SELECTED_WALLET_TYPE: 'SET_SELECTED_WALLET_TYPE',
|
SET_SELECTED_WALLET_TYPE: 'SET_SELECTED_WALLET_TYPE',
|
||||||
INCREMENT_BACKDOOR_PRESSED: 'INCREMENT_BACKDOOR_PRESSED',
|
|
||||||
SET_ENTROPY: 'SET_ENTROPY',
|
SET_ENTROPY: 'SET_ENTROPY',
|
||||||
SET_ENTROPY_BUTTON_TEXT: 'SET_ENTROPY_BUTTON_TEXT',
|
SET_ENTROPY_BUTTON_TEXT: 'SET_ENTROPY_BUTTON_TEXT',
|
||||||
} as const;
|
} as const;
|
||||||
type ActionTypes = (typeof ActionTypes)[keyof typeof ActionTypes];
|
type ActionTypes = (typeof ActionTypes)[keyof typeof ActionTypes];
|
||||||
|
|
||||||
interface Action {
|
interface TAction {
|
||||||
type: ActionTypes;
|
type: ActionTypes;
|
||||||
payload?: any;
|
payload?: any;
|
||||||
}
|
}
|
||||||
|
@ -71,25 +70,22 @@ const initialState: State = {
|
||||||
selectedIndex: 0,
|
selectedIndex: 0,
|
||||||
label: '',
|
label: '',
|
||||||
selectedWalletType: ButtonSelected.ONCHAIN,
|
selectedWalletType: ButtonSelected.ONCHAIN,
|
||||||
backdoorPressed: 1,
|
|
||||||
entropy: undefined,
|
entropy: undefined,
|
||||||
entropyButtonText: loc.wallets.add_entropy_provide,
|
entropyButtonText: loc.wallets.add_entropy_provide,
|
||||||
};
|
};
|
||||||
|
|
||||||
const walletReducer = (state: State, action: Action): State => {
|
const walletReducer = (state: State, action: TAction): State => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case ActionTypes.SET_LOADING:
|
case ActionTypes.SET_LOADING:
|
||||||
return { ...state, isLoading: action.payload };
|
return { ...state, isLoading: action.payload };
|
||||||
case ActionTypes.SET_WALLET_BASE_URI:
|
case ActionTypes.SET_WALLET_BASE_URI:
|
||||||
return { ...state, walletBaseURI: action.payload };
|
return { ...state, walletBaseURI: action.payload };
|
||||||
case ActionTypes.SET_SELECTED_INDEX:
|
case ActionTypes.SET_SELECTED_INDEX:
|
||||||
return { ...state, selectedIndex: action.payload };
|
return { ...state, selectedIndex: action.payload, selectedWalletType: ButtonSelected.ONCHAIN };
|
||||||
case ActionTypes.SET_LABEL:
|
case ActionTypes.SET_LABEL:
|
||||||
return { ...state, label: action.payload };
|
return { ...state, label: action.payload };
|
||||||
case ActionTypes.SET_SELECTED_WALLET_TYPE:
|
case ActionTypes.SET_SELECTED_WALLET_TYPE:
|
||||||
return { ...state, selectedWalletType: action.payload };
|
return { ...state, selectedWalletType: action.payload };
|
||||||
case ActionTypes.INCREMENT_BACKDOOR_PRESSED:
|
|
||||||
return { ...state, backdoorPressed: state.backdoorPressed + 1 };
|
|
||||||
case ActionTypes.SET_ENTROPY:
|
case ActionTypes.SET_ENTROPY:
|
||||||
return { ...state, entropy: action.payload };
|
return { ...state, entropy: action.payload };
|
||||||
case ActionTypes.SET_ENTROPY_BUTTON_TEXT:
|
case ActionTypes.SET_ENTROPY_BUTTON_TEXT:
|
||||||
|
@ -111,10 +107,9 @@ const WalletsAdd: React.FC = () => {
|
||||||
const selectedWalletType = state.selectedWalletType;
|
const selectedWalletType = state.selectedWalletType;
|
||||||
const entropy = state.entropy;
|
const entropy = state.entropy;
|
||||||
const entropyButtonText = state.entropyButtonText;
|
const entropyButtonText = state.entropyButtonText;
|
||||||
//
|
|
||||||
const colorScheme = useColorScheme();
|
const colorScheme = useColorScheme();
|
||||||
|
//
|
||||||
const { addWallet, saveToDisk } = useStorage();
|
const { addWallet, saveToDisk } = useStorage();
|
||||||
const { isAdvancedModeEnabled } = useSettings();
|
|
||||||
const { navigate, goBack, setOptions } = useNavigation();
|
const { navigate, goBack, setOptions } = useNavigation();
|
||||||
const stylesHook = {
|
const stylesHook = {
|
||||||
advancedText: {
|
advancedText: {
|
||||||
|
@ -138,20 +133,7 @@ const WalletsAdd: React.FC = () => {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
const entropyGenerated = useCallback((newEntropy: Buffer) => {
|
||||||
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) => {
|
|
||||||
let entropyTitle;
|
let entropyTitle;
|
||||||
if (!newEntropy) {
|
if (!newEntropy) {
|
||||||
entropyTitle = loc.wallets.add_entropy_provide;
|
entropyTitle = loc.wallets.add_entropy_provide;
|
||||||
|
@ -162,8 +144,128 @@ const WalletsAdd: React.FC = () => {
|
||||||
}
|
}
|
||||||
setEntropy(newEntropy);
|
setEntropy(newEntropy);
|
||||||
setEntropyButtonText(entropyTitle);
|
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,
|
||||||
|
menuState: selectedWalletType === ButtonSelected.OFFCHAIN,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const walletAction: Action = {
|
||||||
|
id: 'wallets',
|
||||||
|
text: loc.multisig.wallet_type,
|
||||||
|
subactions: walletSubactions,
|
||||||
|
displayInline: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const entropyAction = {
|
||||||
|
...CommonToolTipActions.Entropy,
|
||||||
|
text: entropyButtonText,
|
||||||
|
menuState: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
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) => {
|
const setIsLoading = (value: boolean) => {
|
||||||
dispatch({ type: 'SET_LOADING', payload: value });
|
dispatch({ type: 'SET_LOADING', payload: value });
|
||||||
};
|
};
|
||||||
|
@ -184,10 +286,6 @@ const WalletsAdd: React.FC = () => {
|
||||||
dispatch({ type: 'SET_SELECTED_WALLET_TYPE', payload: value });
|
dispatch({ type: 'SET_SELECTED_WALLET_TYPE', payload: value });
|
||||||
};
|
};
|
||||||
|
|
||||||
const setBackdoorPressed = (value: number) => {
|
|
||||||
dispatch({ type: 'INCREMENT_BACKDOOR_PRESSED', payload: value });
|
|
||||||
};
|
|
||||||
|
|
||||||
const setEntropy = (value: Buffer) => {
|
const setEntropy = (value: Buffer) => {
|
||||||
dispatch({ type: 'SET_ENTROPY', payload: value });
|
dispatch({ type: 'SET_ENTROPY', payload: value });
|
||||||
};
|
};
|
||||||
|
@ -225,7 +323,6 @@ const WalletsAdd: React.FC = () => {
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
console.log(e.toString());
|
console.log(e.toString());
|
||||||
presentAlert({ message: e.toString() });
|
presentAlert({ message: e.toString() });
|
||||||
goBack();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -291,37 +388,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 = () => {
|
const navigateToImportWallet = () => {
|
||||||
// @ts-ignore: Return later to update
|
// @ts-ignore: Return later to update
|
||||||
navigate('ImportWallet');
|
navigate('ImportWallet');
|
||||||
|
@ -339,16 +405,6 @@ const WalletsAdd: React.FC = () => {
|
||||||
setSelectedWalletType(ButtonSelected.ONCHAIN);
|
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);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ScrollView style={stylesHook.root} testID="ScrollView" automaticallyAdjustKeyboardInsets>
|
<ScrollView style={stylesHook.root} testID="ScrollView" automaticallyAdjustKeyboardInsets>
|
||||||
<BlueSpacing20 />
|
<BlueSpacing20 />
|
||||||
|
@ -374,12 +430,6 @@ const WalletsAdd: React.FC = () => {
|
||||||
onPress={handleOnBitcoinButtonPressed}
|
onPress={handleOnBitcoinButtonPressed}
|
||||||
size={styles.button}
|
size={styles.button}
|
||||||
/>
|
/>
|
||||||
<WalletButton
|
|
||||||
buttonType="Lightning"
|
|
||||||
active={selectedWalletType === ButtonSelected.OFFCHAIN}
|
|
||||||
onPress={handleOnLightningButtonPressed}
|
|
||||||
size={styles.button}
|
|
||||||
/>
|
|
||||||
<WalletButton
|
<WalletButton
|
||||||
buttonType="Vault"
|
buttonType="Vault"
|
||||||
testID="ActivateVaultButton"
|
testID="ActivateVaultButton"
|
||||||
|
@ -390,40 +440,8 @@ const WalletsAdd: React.FC = () => {
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
<View style={styles.advanced}>
|
<View style={styles.advanced}>
|
||||||
{(() => {
|
{selectedWalletType === ButtonSelected.OFFCHAIN && (
|
||||||
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 />
|
<BlueSpacing20 />
|
||||||
<BlueText>{loc.wallets.add_lndhub}</BlueText>
|
<BlueText>{loc.wallets.add_lndhub}</BlueText>
|
||||||
<View style={[styles.lndUri, stylesHook.lndUri]}>
|
<View style={[styles.lndUri, stylesHook.lndUri]}>
|
||||||
|
@ -443,12 +461,8 @@ const WalletsAdd: React.FC = () => {
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
</>
|
</>
|
||||||
);
|
|
||||||
}
|
|
||||||
})()}
|
|
||||||
{isAdvancedModeEnabled === true && selectedWalletType === ButtonSelected.ONCHAIN && !isLoading && (
|
|
||||||
<BlueButtonLink style={styles.import} title={entropyButtonText} onPress={navigateToEntropy} />
|
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<BlueSpacing20 />
|
<BlueSpacing20 />
|
||||||
{!isLoading ? (
|
{!isLoading ? (
|
||||||
<>
|
<>
|
||||||
|
@ -508,9 +522,6 @@ const styles = StyleSheet.create({
|
||||||
advanced: {
|
advanced: {
|
||||||
marginHorizontal: 20,
|
marginHorizontal: 20,
|
||||||
},
|
},
|
||||||
advancedText: {
|
|
||||||
fontWeight: '500',
|
|
||||||
},
|
|
||||||
lndUri: {
|
lndUri: {
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
borderWidth: 1,
|
borderWidth: 1,
|
||||||
|
@ -524,9 +535,6 @@ const styles = StyleSheet.create({
|
||||||
import: {
|
import: {
|
||||||
marginVertical: 24,
|
marginVertical: 24,
|
||||||
},
|
},
|
||||||
noPadding: {
|
|
||||||
paddingHorizontal: 0,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export default WalletsAdd;
|
export default WalletsAdd;
|
||||||
|
|
|
@ -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 { useFocusEffect, useRoute } from '@react-navigation/native';
|
||||||
import {
|
import {
|
||||||
ActivityIndicator,
|
ActivityIndicator,
|
||||||
|
@ -11,7 +11,6 @@ import {
|
||||||
ListRenderItemInfo,
|
ListRenderItemInfo,
|
||||||
Platform,
|
Platform,
|
||||||
StyleSheet,
|
StyleSheet,
|
||||||
Switch,
|
|
||||||
Text,
|
Text,
|
||||||
View,
|
View,
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
|
@ -20,12 +19,11 @@ import { isDesktop } from '../../blue_modules/environment';
|
||||||
import { encodeUR } from '../../blue_modules/ur';
|
import { encodeUR } from '../../blue_modules/ur';
|
||||||
import {
|
import {
|
||||||
BlueButtonLink,
|
BlueButtonLink,
|
||||||
|
BlueCard,
|
||||||
BlueFormMultiInput,
|
BlueFormMultiInput,
|
||||||
BlueLoading,
|
BlueLoading,
|
||||||
BlueSpacing10,
|
BlueSpacing10,
|
||||||
BlueSpacing20,
|
BlueSpacing20,
|
||||||
BlueSpacing40,
|
|
||||||
BlueText,
|
|
||||||
BlueTextCentered,
|
BlueTextCentered,
|
||||||
} from '../../BlueComponents';
|
} from '../../BlueComponents';
|
||||||
import { HDSegwitBech32Wallet, MultisigCosigner, MultisigHDWallet } from '../../class';
|
import { HDSegwitBech32Wallet, MultisigCosigner, MultisigHDWallet } from '../../class';
|
||||||
|
@ -49,14 +47,14 @@ import usePrivacy from '../../hooks/usePrivacy';
|
||||||
import loc from '../../loc';
|
import loc from '../../loc';
|
||||||
import ActionSheet from '../ActionSheet';
|
import ActionSheet from '../ActionSheet';
|
||||||
import { useStorage } from '../../hooks/context/useStorage';
|
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 ViewEditMultisigCosigners: React.FC = () => {
|
||||||
const hasLoaded = useRef(false);
|
const hasLoaded = useRef(false);
|
||||||
const { colors } = useTheme();
|
const { colors } = useTheme();
|
||||||
const { wallets, setWalletsWithNewOrder, isElectrumDisabled } = useStorage();
|
const { wallets, setWalletsWithNewOrder, isElectrumDisabled } = useStorage();
|
||||||
const { isBiometricUseCapableAndEnabled } = useBiometrics();
|
const { isBiometricUseCapableAndEnabled } = useBiometrics();
|
||||||
const { isAdvancedModeEnabled } = useSettings();
|
|
||||||
const { navigate, dispatch, addListener } = useExtendedNavigation();
|
const { navigate, dispatch, addListener } = useExtendedNavigation();
|
||||||
const openScannerButtonRef = useRef();
|
const openScannerButtonRef = useRef();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
@ -97,6 +95,9 @@ const ViewEditMultisigCosigners: React.FC = () => {
|
||||||
vaultKeyText: {
|
vaultKeyText: {
|
||||||
color: colors.alternativeTextColor,
|
color: colors.alternativeTextColor,
|
||||||
},
|
},
|
||||||
|
askPassphrase: {
|
||||||
|
backgroundColor: colors.lightButton,
|
||||||
|
},
|
||||||
vaultKeyCircleSuccess: {
|
vaultKeyCircleSuccess: {
|
||||||
backgroundColor: colors.msSuccessBG,
|
backgroundColor: colors.msSuccessBG,
|
||||||
},
|
},
|
||||||
|
@ -523,6 +524,12 @@ const ViewEditMultisigCosigners: React.FC = () => {
|
||||||
|
|
||||||
const hideShareModal = () => {};
|
const hideShareModal = () => {};
|
||||||
|
|
||||||
|
const toolTipActions = useMemo(() => {
|
||||||
|
const passphrase = CommonToolTipActions.Passphrase;
|
||||||
|
passphrase.menuState = askPassphrase;
|
||||||
|
return [passphrase];
|
||||||
|
}, [askPassphrase]);
|
||||||
|
|
||||||
const renderProvideMnemonicsModal = () => {
|
const renderProvideMnemonicsModal = () => {
|
||||||
return (
|
return (
|
||||||
<BottomModal
|
<BottomModal
|
||||||
|
@ -545,18 +552,24 @@ const ViewEditMultisigCosigners: React.FC = () => {
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
<>
|
||||||
|
<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>
|
<BlueTextCentered>{loc.multisig.type_your_mnemonics}</BlueTextCentered>
|
||||||
<BlueSpacing20 />
|
<BlueSpacing20 />
|
||||||
<BlueFormMultiInput value={importText} onChangeText={setImportText} />
|
<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>
|
|
||||||
</>
|
</>
|
||||||
)}
|
|
||||||
</BottomModal>
|
</BottomModal>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -639,10 +652,11 @@ const ViewEditMultisigCosigners: React.FC = () => {
|
||||||
contentInsetAdjustmentBehavior="automatic"
|
contentInsetAdjustmentBehavior="automatic"
|
||||||
automaticallyAdjustContentInsets
|
automaticallyAdjustContentInsets
|
||||||
keyExtractor={(_item, index) => `${index}`}
|
keyExtractor={(_item, index) => `${index}`}
|
||||||
|
contentContainerStyle={styles.contentContainerStyle}
|
||||||
/>
|
/>
|
||||||
<BlueSpacing10 />
|
<BlueSpacing10 />
|
||||||
{footer}
|
<BlueCard>{footer}</BlueCard>
|
||||||
<BlueSpacing40 />
|
<BlueSpacing20 />
|
||||||
|
|
||||||
{renderProvideMnemonicsModal()}
|
{renderProvideMnemonicsModal()}
|
||||||
|
|
||||||
|
@ -665,6 +679,7 @@ const styles = StyleSheet.create({
|
||||||
paddingTop: 32,
|
paddingTop: 32,
|
||||||
minHeight: 370,
|
minHeight: 370,
|
||||||
},
|
},
|
||||||
|
contentContainerStyle: { padding: 16 },
|
||||||
modalContent: {
|
modalContent: {
|
||||||
padding: 22,
|
padding: 22,
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
|
@ -700,12 +715,8 @@ const styles = StyleSheet.create({
|
||||||
tipLabelText: {
|
tipLabelText: {
|
||||||
fontWeight: '500',
|
fontWeight: '500',
|
||||||
},
|
},
|
||||||
row: {
|
|
||||||
flexDirection: 'row',
|
askPassprase: { top: 0, left: 0, justifyContent: 'center', width: 33, height: 33, borderRadius: 33 / 2 },
|
||||||
alignItems: 'center',
|
|
||||||
marginHorizontal: 16,
|
|
||||||
justifyContent: 'space-between',
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export default ViewEditMultisigCosigners;
|
export default ViewEditMultisigCosigners;
|
||||||
|
|
|
@ -11,7 +11,6 @@ import ListItem from '../../components/ListItem';
|
||||||
import SafeArea from '../../components/SafeArea';
|
import SafeArea from '../../components/SafeArea';
|
||||||
import { useTheme } from '../../components/themes';
|
import { useTheme } from '../../components/themes';
|
||||||
import loc from '../../loc';
|
import loc from '../../loc';
|
||||||
import { useSettings } from '../../hooks/context/useSettings';
|
|
||||||
import { NativeStackNavigationProp } from '@react-navigation/native-stack';
|
import { NativeStackNavigationProp } from '@react-navigation/native-stack';
|
||||||
import { useExtendedNavigation } from '../../hooks/useExtendedNavigation';
|
import { useExtendedNavigation } from '../../hooks/useExtendedNavigation';
|
||||||
import { AddWalletStackParamList } from '../../navigation/AddWalletStack';
|
import { AddWalletStackParamList } from '../../navigation/AddWalletStack';
|
||||||
|
@ -27,7 +26,6 @@ const WalletsAddMultisig: React.FC = () => {
|
||||||
const [m, setM] = useState(2);
|
const [m, setM] = useState(2);
|
||||||
const [n, setN] = useState(3);
|
const [n, setN] = useState(3);
|
||||||
const [format, setFormat] = useState(MultisigHDWallet.FORMAT_P2WSH);
|
const [format, setFormat] = useState(MultisigHDWallet.FORMAT_P2WSH);
|
||||||
const { isAdvancedModeEnabled } = useSettings();
|
|
||||||
|
|
||||||
const stylesHook = StyleSheet.create({
|
const stylesHook = StyleSheet.create({
|
||||||
root: {
|
root: {
|
||||||
|
@ -202,7 +200,6 @@ const WalletsAddMultisig: React.FC = () => {
|
||||||
</Text>
|
</Text>
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
{isAdvancedModeEnabled && (
|
|
||||||
<View>
|
<View>
|
||||||
<ListItem
|
<ListItem
|
||||||
testID="VaultAdvancedCustomize"
|
testID="VaultAdvancedCustomize"
|
||||||
|
@ -212,7 +209,7 @@ const WalletsAddMultisig: React.FC = () => {
|
||||||
chevron
|
chevron
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
)}
|
|
||||||
<View style={styles.buttonContainer}>
|
<View style={styles.buttonContainer}>
|
||||||
<Button
|
<Button
|
||||||
testID="LetsStart"
|
testID="LetsStart"
|
||||||
|
|
|
@ -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 { useFocusEffect, useRoute } from '@react-navigation/native';
|
||||||
import {
|
import {
|
||||||
ActivityIndicator,
|
ActivityIndicator,
|
||||||
|
@ -8,7 +8,6 @@ import {
|
||||||
LayoutAnimation,
|
LayoutAnimation,
|
||||||
Platform,
|
Platform,
|
||||||
StyleSheet,
|
StyleSheet,
|
||||||
Switch,
|
|
||||||
Text,
|
Text,
|
||||||
TouchableOpacity,
|
TouchableOpacity,
|
||||||
View,
|
View,
|
||||||
|
@ -17,7 +16,7 @@ import { Icon } from '@rneui/themed';
|
||||||
import A from '../../blue_modules/analytics';
|
import A from '../../blue_modules/analytics';
|
||||||
import triggerHapticFeedback, { HapticFeedbackTypes } from '../../blue_modules/hapticFeedback';
|
import triggerHapticFeedback, { HapticFeedbackTypes } from '../../blue_modules/hapticFeedback';
|
||||||
import { encodeUR } from '../../blue_modules/ur';
|
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 { HDSegwitBech32Wallet, MultisigCosigner, MultisigHDWallet } from '../../class';
|
||||||
import presentAlert from '../../components/Alert';
|
import presentAlert from '../../components/Alert';
|
||||||
import BottomModal from '../../components/BottomModal';
|
import BottomModal from '../../components/BottomModal';
|
||||||
|
@ -35,15 +34,15 @@ import prompt from '../../helpers/prompt';
|
||||||
import usePrivacy from '../../hooks/usePrivacy';
|
import usePrivacy from '../../hooks/usePrivacy';
|
||||||
import loc from '../../loc';
|
import loc from '../../loc';
|
||||||
import { useStorage } from '../../hooks/context/useStorage';
|
import { useStorage } from '../../hooks/context/useStorage';
|
||||||
import { useSettings } from '../../hooks/context/useSettings';
|
|
||||||
import { scanQrHelper } from '../../helpers/scan-qr';
|
import { scanQrHelper } from '../../helpers/scan-qr';
|
||||||
import { useExtendedNavigation } from '../../hooks/useExtendedNavigation';
|
import { useExtendedNavigation } from '../../hooks/useExtendedNavigation';
|
||||||
|
import ToolTipMenu from '../../components/TooltipMenu';
|
||||||
|
import { CommonToolTipActions } from '../../typings/CommonToolTipActions';
|
||||||
|
|
||||||
const staticCache = {};
|
const staticCache = {};
|
||||||
|
|
||||||
const WalletsAddMultisigStep2 = () => {
|
const WalletsAddMultisigStep2 = () => {
|
||||||
const { addWallet, saveToDisk, isElectrumDisabled, sleep, currentSharedCosigner, setSharedCosigner } = useStorage();
|
const { addWallet, saveToDisk, isElectrumDisabled, sleep, currentSharedCosigner, setSharedCosigner } = useStorage();
|
||||||
const { isAdvancedModeEnabled } = useSettings();
|
|
||||||
const { colors } = useTheme();
|
const { colors } = useTheme();
|
||||||
|
|
||||||
const { navigate, navigateToWalletsList } = useExtendedNavigation();
|
const { navigate, navigateToWalletsList } = useExtendedNavigation();
|
||||||
|
@ -108,6 +107,9 @@ const WalletsAddMultisigStep2 = () => {
|
||||||
root: {
|
root: {
|
||||||
backgroundColor: colors.elevated,
|
backgroundColor: colors.elevated,
|
||||||
},
|
},
|
||||||
|
askPassphrase: {
|
||||||
|
backgroundColor: colors.lightButton,
|
||||||
|
},
|
||||||
textDestination: {
|
textDestination: {
|
||||||
color: colors.foregroundColor,
|
color: colors.foregroundColor,
|
||||||
},
|
},
|
||||||
|
@ -611,6 +613,12 @@ const WalletsAddMultisigStep2 = () => {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const toolTipActions = useMemo(() => {
|
||||||
|
const passphrase = CommonToolTipActions.Passphrase;
|
||||||
|
passphrase.menuState = askPassphrase;
|
||||||
|
return [passphrase];
|
||||||
|
}, [askPassphrase]);
|
||||||
|
|
||||||
const renderProvideMnemonicsModal = () => {
|
const renderProvideMnemonicsModal = () => {
|
||||||
return (
|
return (
|
||||||
<BottomModal
|
<BottomModal
|
||||||
|
@ -648,18 +656,24 @@ const WalletsAddMultisigStep2 = () => {
|
||||||
setAskPassphrase(false);
|
setAskPassphrase(false);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
<>
|
||||||
|
<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>
|
<BlueTextCentered>{loc.multisig.type_your_mnemonics}</BlueTextCentered>
|
||||||
<BlueSpacing20 />
|
<BlueSpacing20 />
|
||||||
<BlueFormMultiInput value={importText} onChangeText={setImportText} />
|
<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>
|
|
||||||
</>
|
</>
|
||||||
)}
|
|
||||||
</BottomModal>
|
</BottomModal>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -798,6 +812,8 @@ const styles = StyleSheet.create({
|
||||||
paddingRight: 8,
|
paddingRight: 8,
|
||||||
borderRadius: 4,
|
borderRadius: 4,
|
||||||
},
|
},
|
||||||
|
askPassprase: { top: 0, left: 0, justifyContent: 'center', width: 33, height: 33, borderRadius: 33 / 2 },
|
||||||
|
|
||||||
secretContainer: {
|
secretContainer: {
|
||||||
flexDirection: I18nManager.isRTL ? 'row-reverse' : 'row',
|
flexDirection: I18nManager.isRTL ? 'row-reverse' : 'row',
|
||||||
justifyContent: 'flex-start',
|
justifyContent: 'flex-start',
|
||||||
|
@ -829,12 +845,6 @@ const styles = StyleSheet.create({
|
||||||
fontWeight: 'bold',
|
fontWeight: 'bold',
|
||||||
marginLeft: 8,
|
marginLeft: 8,
|
||||||
},
|
},
|
||||||
row: {
|
|
||||||
flexDirection: 'row',
|
|
||||||
alignItems: 'center',
|
|
||||||
marginHorizontal: 16,
|
|
||||||
justifyContent: 'space-between',
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export default WalletsAddMultisigStep2;
|
export default WalletsAddMultisigStep2;
|
||||||
|
|
|
@ -41,10 +41,9 @@ import { unlockWithBiometrics, useBiometrics } from '../../hooks/useBiometrics';
|
||||||
import { useExtendedNavigation } from '../../hooks/useExtendedNavigation';
|
import { useExtendedNavigation } from '../../hooks/useExtendedNavigation';
|
||||||
import loc, { formatBalanceWithoutSuffix } from '../../loc';
|
import loc, { formatBalanceWithoutSuffix } from '../../loc';
|
||||||
import { BitcoinUnit, Chain } from '../../models/bitcoinUnits';
|
import { BitcoinUnit, Chain } from '../../models/bitcoinUnits';
|
||||||
import { useSettings } from '../../hooks/context/useSettings';
|
|
||||||
import { useStorage } from '../../hooks/context/useStorage';
|
import { useStorage } from '../../hooks/context/useStorage';
|
||||||
import { popToTop } from '../../NavigationService';
|
import { popToTop } from '../../NavigationService';
|
||||||
import { useRoute } from '@react-navigation/native';
|
import { useFocusEffect, useRoute } from '@react-navigation/native';
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
scrollViewContent: {
|
scrollViewContent: {
|
||||||
|
@ -113,7 +112,6 @@ const WalletDetails = () => {
|
||||||
const wallet = useRef(wallets.find(w => w.getID() === walletID)).current;
|
const wallet = useRef(wallets.find(w => w.getID() === walletID)).current;
|
||||||
const [walletName, setWalletName] = useState(wallet.getLabel());
|
const [walletName, setWalletName] = useState(wallet.getLabel());
|
||||||
const [useWithHardwareWallet, setUseWithHardwareWallet] = useState(wallet.useWithHardwareWalletEnabled());
|
const [useWithHardwareWallet, setUseWithHardwareWallet] = useState(wallet.useWithHardwareWalletEnabled());
|
||||||
const { isAdvancedModeEnabled } = useSettings();
|
|
||||||
const [isBIP47Enabled, setIsBIP47Enabled] = useState(wallet.isBIP47Enabled());
|
const [isBIP47Enabled, setIsBIP47Enabled] = useState(wallet.isBIP47Enabled());
|
||||||
const [isContactsVisible, setIsContactsVisible] = useState(wallet.allowBIP47() && wallet.isBIP47Enabled());
|
const [isContactsVisible, setIsContactsVisible] = useState(wallet.allowBIP47() && wallet.isBIP47Enabled());
|
||||||
const [hideTransactionsInWalletsList, setHideTransactionsInWalletsList] = useState(!wallet.getHideTransactionsInWalletsList());
|
const [hideTransactionsInWalletsList, setHideTransactionsInWalletsList] = useState(!wallet.getHideTransactionsInWalletsList());
|
||||||
|
@ -138,13 +136,17 @@ const WalletDetails = () => {
|
||||||
setIsContactsVisible(isBIP47Enabled);
|
setIsContactsVisible(isBIP47Enabled);
|
||||||
}, [isBIP47Enabled]);
|
}, [isBIP47Enabled]);
|
||||||
|
|
||||||
useEffect(() => {
|
useFocusEffect(
|
||||||
if (isAdvancedModeEnabled && wallet.allowMasterFingerprint()) {
|
useCallback(() => {
|
||||||
InteractionManager.runAfterInteractions(() => {
|
const task = InteractionManager.runAfterInteractions(() => {
|
||||||
|
if (wallet.allowMasterFingerprint()) {
|
||||||
setMasterFingerprint(wallet.getMasterFingerprintHex());
|
setMasterFingerprint(wallet.getMasterFingerprintHex());
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}, [isAdvancedModeEnabled, wallet]);
|
});
|
||||||
|
|
||||||
|
return () => task.cancel();
|
||||||
|
}, [wallet]),
|
||||||
|
);
|
||||||
const stylesHook = StyleSheet.create({
|
const stylesHook = StyleSheet.create({
|
||||||
textLabel1: {
|
textLabel1: {
|
||||||
color: colors.feeText,
|
color: colors.feeText,
|
||||||
|
@ -541,13 +543,10 @@ const WalletDetails = () => {
|
||||||
</View>
|
</View>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{isAdvancedModeEnabled && (
|
|
||||||
<View style={styles.row}>
|
<View style={styles.row}>
|
||||||
{wallet.allowMasterFingerprint() && (
|
{wallet.allowMasterFingerprint() && (
|
||||||
<View style={styles.marginRight16}>
|
<View style={styles.marginRight16}>
|
||||||
<Text style={[styles.textLabel2, stylesHook.textLabel2]}>
|
<Text style={[styles.textLabel2, stylesHook.textLabel2]}>{loc.wallets.details_master_fingerprint.toLowerCase()}</Text>
|
||||||
{loc.wallets.details_master_fingerprint.toLowerCase()}
|
|
||||||
</Text>
|
|
||||||
<BlueText>{masterFingerprint ?? <ActivityIndicator />}</BlueText>
|
<BlueText>{masterFingerprint ?? <ActivityIndicator />}</BlueText>
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
|
@ -559,7 +558,6 @@ const WalletDetails = () => {
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
)}
|
|
||||||
</View>
|
</View>
|
||||||
</BlueCard>
|
</BlueCard>
|
||||||
{(wallet instanceof AbstractHDElectrumWallet || (wallet.type === WatchOnlyWallet.type && wallet.isHd())) && (
|
{(wallet instanceof AbstractHDElectrumWallet || (wallet.type === WatchOnlyWallet.type && wallet.isHd())) && (
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { useNavigation, useRoute } from '@react-navigation/native';
|
import { useRoute } from '@react-navigation/native';
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState, useMemo, useCallback } from 'react';
|
||||||
import { Keyboard, Platform, StyleSheet, Switch, TouchableWithoutFeedback, View } from 'react-native';
|
import { Keyboard, Platform, StyleSheet, TouchableWithoutFeedback, View, ScrollView } from 'react-native';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
BlueButtonLink,
|
BlueButtonLink,
|
||||||
|
@ -8,24 +8,25 @@ import {
|
||||||
BlueFormLabel,
|
BlueFormLabel,
|
||||||
BlueFormMultiInput,
|
BlueFormMultiInput,
|
||||||
BlueSpacing20,
|
BlueSpacing20,
|
||||||
BlueText,
|
|
||||||
} from '../../BlueComponents';
|
} from '../../BlueComponents';
|
||||||
import Button from '../../components/Button';
|
import Button from '../../components/Button';
|
||||||
import SafeArea from '../../components/SafeArea';
|
|
||||||
import { useTheme } from '../../components/themes';
|
import { useTheme } from '../../components/themes';
|
||||||
import { requestCameraAuthorization } from '../../helpers/scan-qr';
|
import { requestCameraAuthorization } from '../../helpers/scan-qr';
|
||||||
import usePrivacy from '../../hooks/usePrivacy';
|
import usePrivacy from '../../hooks/usePrivacy';
|
||||||
import loc from '../../loc';
|
import loc from '../../loc';
|
||||||
import { useSettings } from '../../hooks/context/useSettings';
|
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 WalletsImport = () => {
|
||||||
const navigation = useNavigation();
|
const navigation = useExtendedNavigation();
|
||||||
const { colors } = useTheme();
|
const { colors } = useTheme();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const label = route?.params?.label ?? '';
|
const label = route?.params?.label ?? '';
|
||||||
const triggerImport = route?.params?.triggerImport ?? false;
|
const triggerImport = route?.params?.triggerImport ?? false;
|
||||||
const scannedData = route?.params?.scannedData ?? '';
|
const scannedData = route?.params?.scannedData ?? '';
|
||||||
const { isAdvancedModeEnabled } = useSettings();
|
|
||||||
const [importText, setImportText] = useState(label);
|
const [importText, setImportText] = useState(label);
|
||||||
const [isToolbarVisibleForAndroid, setIsToolbarVisibleForAndroid] = useState(false);
|
const [isToolbarVisibleForAndroid, setIsToolbarVisibleForAndroid] = useState(false);
|
||||||
const [, setSpeedBackdoor] = useState(0);
|
const [, setSpeedBackdoor] = useState(0);
|
||||||
|
@ -33,23 +34,18 @@ const WalletsImport = () => {
|
||||||
const [askPassphrase, setAskPassphrase] = useState(false);
|
const [askPassphrase, setAskPassphrase] = useState(false);
|
||||||
const { enableBlur, disableBlur } = usePrivacy();
|
const { enableBlur, disableBlur } = usePrivacy();
|
||||||
|
|
||||||
|
// Styles
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
root: {
|
root: {
|
||||||
paddingTop: 10,
|
paddingTop: 10,
|
||||||
backgroundColor: colors.elevated,
|
backgroundColor: colors.elevated,
|
||||||
|
flex: 1,
|
||||||
},
|
},
|
||||||
center: {
|
center: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
marginHorizontal: 16,
|
marginHorizontal: 16,
|
||||||
backgroundColor: colors.elevated,
|
backgroundColor: colors.elevated,
|
||||||
},
|
},
|
||||||
row: {
|
|
||||||
flexDirection: 'row',
|
|
||||||
alignItems: 'center',
|
|
||||||
marginHorizontal: 16,
|
|
||||||
marginTop: 10,
|
|
||||||
justifyContent: 'space-between',
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const onBlur = () => {
|
const onBlur = () => {
|
||||||
|
@ -58,18 +54,18 @@ const WalletsImport = () => {
|
||||||
return valueWithSingleWhitespace;
|
return valueWithSingleWhitespace;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
useKeyboard({
|
||||||
|
onKeyboardDidShow: () => {
|
||||||
|
setIsToolbarVisibleForAndroid(true);
|
||||||
|
},
|
||||||
|
onKeyboardDidHide: () => {
|
||||||
|
setIsToolbarVisibleForAndroid(false);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
enableBlur();
|
enableBlur();
|
||||||
|
|
||||||
const showSubscription = Keyboard.addListener(Platform.OS === 'ios' ? 'keyboardWillShow' : 'keyboardDidShow', () =>
|
|
||||||
setIsToolbarVisibleForAndroid(true),
|
|
||||||
);
|
|
||||||
const hideSubscription = Keyboard.addListener(Platform.OS === 'ios' ? 'keyboardWillHide' : 'keyboardDidHide', () =>
|
|
||||||
setIsToolbarVisibleForAndroid(false),
|
|
||||||
);
|
|
||||||
return () => {
|
return () => {
|
||||||
showSubscription.remove();
|
|
||||||
hideSubscription.remove();
|
|
||||||
disableBlur();
|
disableBlur();
|
||||||
};
|
};
|
||||||
}, [disableBlur, enableBlur]);
|
}, [disableBlur, enableBlur]);
|
||||||
|
@ -125,21 +121,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 = (
|
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 />
|
<BlueSpacing20 />
|
||||||
<View style={styles.center}>
|
<View style={styles.center}>
|
||||||
<>
|
<>
|
||||||
|
@ -157,7 +183,14 @@ const WalletsImport = () => {
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SafeArea style={styles.root}>
|
<ScrollView
|
||||||
|
contentContainerStyle={styles.root}
|
||||||
|
automaticallyAdjustContentInsets
|
||||||
|
automaticallyAdjustsScrollIndicatorInsets
|
||||||
|
keyboardShouldPersistTaps
|
||||||
|
automaticallyAdjustKeyboardInsets
|
||||||
|
contentInsetAdjustmentBehavior="automatic"
|
||||||
|
>
|
||||||
<BlueSpacing20 />
|
<BlueSpacing20 />
|
||||||
<TouchableWithoutFeedback accessibilityRole="button" onPress={speedBackdoorTap} testID="SpeedBackdoor">
|
<TouchableWithoutFeedback accessibilityRole="button" onPress={speedBackdoorTap} testID="SpeedBackdoor">
|
||||||
<BlueFormLabel>{loc.wallets.import_explanation}</BlueFormLabel>
|
<BlueFormLabel>{loc.wallets.import_explanation}</BlueFormLabel>
|
||||||
|
@ -197,7 +230,7 @@ const WalletsImport = () => {
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
})}
|
})}
|
||||||
</SafeArea>
|
</ScrollView>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,7 @@
|
||||||
import assert from 'assert';
|
import assert from 'assert';
|
||||||
import * as bitcoin from 'bitcoinjs-lib';
|
import * as bitcoin from 'bitcoinjs-lib';
|
||||||
|
|
||||||
import {
|
import { expectToBeVisible, extractTextFromElementById, hashIt, helperCreateWallet, helperDeleteWallet, sleep, sup, yo } from './helperz';
|
||||||
expectToBeVisible,
|
|
||||||
extractTextFromElementById,
|
|
||||||
hashIt,
|
|
||||||
helperCreateWallet,
|
|
||||||
helperDeleteWallet,
|
|
||||||
helperSwitchAdvancedMode,
|
|
||||||
sleep,
|
|
||||||
sup,
|
|
||||||
yo,
|
|
||||||
} from './helperz';
|
|
||||||
import { element } from 'detox';
|
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 element(by.id('QuickActionsSwitch')).tap();
|
await element(by.id('QuickActionsSwitch')).tap();
|
||||||
await device.pressBack();
|
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
|
// currency
|
||||||
// change currency to ARS ($) and switch it back to USD ($)
|
// 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');
|
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 device.launchApp({ delete: true }); // reinstalling the app just for any case to clean up app's storage
|
||||||
await helperSwitchAdvancedMode();
|
|
||||||
await yo('WalletsList');
|
await yo('WalletsList');
|
||||||
await element(by.id('WalletsList')).swipe('left', 'fast', 1); // in case emu screen is small and it doesnt fit
|
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.
|
await sleep(200); // Wait until bounce animation finishes.
|
||||||
|
@ -542,7 +525,6 @@ describe('BlueWallet UI Tests - no wallets', () => {
|
||||||
|
|
||||||
await device.pressBack();
|
await device.pressBack();
|
||||||
await helperDeleteWallet('Multisig Vault');
|
await helperDeleteWallet('Multisig Vault');
|
||||||
await helperSwitchAdvancedMode(); // turn off advanced mode
|
|
||||||
process.env.TRAVIS && require('fs').writeFileSync(lockFile, '1');
|
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 device.launchApp({ delete: true }); // reinstalling the app just for any case to clean up app's storage
|
||||||
await yo('WalletsList');
|
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 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.
|
await sleep(200); // Wait until bounce animation finishes.
|
||||||
// going to Import Wallet screen and importing mnemonic
|
// going to Import Wallet screen and importing mnemonic
|
||||||
|
@ -698,8 +677,10 @@ describe('BlueWallet UI Tests - no wallets', () => {
|
||||||
await element(by.id('MnemonicInput')).replaceText(
|
await element(by.id('MnemonicInput')).replaceText(
|
||||||
'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about',
|
'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about',
|
||||||
);
|
);
|
||||||
await element(by.id('AskPassphrase')).tap();
|
await element(by.id('HeaderRightButton')).tap();
|
||||||
await element(by.id('SearchAccounts')).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 element(by.id('DoImport')).tap();
|
||||||
await sleep(1000);
|
await sleep(1000);
|
||||||
|
|
||||||
|
@ -734,7 +715,6 @@ describe('BlueWallet UI Tests - no wallets', () => {
|
||||||
await device.pressBack();
|
await device.pressBack();
|
||||||
await device.pressBack();
|
await device.pressBack();
|
||||||
await helperDeleteWallet('Imported HD Legacy (BIP44 P2PKH)');
|
await helperDeleteWallet('Imported HD Legacy (BIP44 P2PKH)');
|
||||||
await helperSwitchAdvancedMode();
|
|
||||||
|
|
||||||
process.env.TRAVIS && require('fs').writeFileSync(lockFile, '1');
|
process.env.TRAVIS && require('fs').writeFileSync(lockFile, '1');
|
||||||
});
|
});
|
||||||
|
|
|
@ -382,6 +382,7 @@ describe('BlueWallet UI Tests - import BIP84 wallet', () => {
|
||||||
if (!(await getSwitchValue('BIP47Switch'))) {
|
if (!(await getSwitchValue('BIP47Switch'))) {
|
||||||
await expect(element(by.text('Contacts'))).not.toBeVisible();
|
await expect(element(by.text('Contacts'))).not.toBeVisible();
|
||||||
await element(by.id('BIP47Switch')).tap();
|
await element(by.id('BIP47Switch')).tap();
|
||||||
|
await element(by.id('WalletDetailsScroll')).swipe('up', 'fast', 1);
|
||||||
await expect(element(by.text('Contacts'))).toBeVisible();
|
await expect(element(by.text('Contacts'))).toBeVisible();
|
||||||
await element(by.text('Save')).tap(); // automatically goes back 1 screen
|
await element(by.text('Save')).tap(); // automatically goes back 1 screen
|
||||||
await element(by.text('OK')).tap();
|
await element(by.text('OK')).tap();
|
||||||
|
|
|
@ -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 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();
|
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();
|
|
||||||
}
|
|
||||||
|
|
|
@ -11,6 +11,12 @@ const keys = {
|
||||||
ViewInBitcoin: 'viewInBitcoin',
|
ViewInBitcoin: 'viewInBitcoin',
|
||||||
ViewInSats: 'viewInSats',
|
ViewInSats: 'viewInSats',
|
||||||
ViewInFiat: 'viewInFiat',
|
ViewInFiat: 'viewInFiat',
|
||||||
|
Entropy: 'entropy',
|
||||||
|
SearchAccount: 'searchAccount',
|
||||||
|
Passphrase: 'passphrase',
|
||||||
|
MoreInfo: 'moreInfo',
|
||||||
|
SaveChanges: 'saveChanges',
|
||||||
|
PaymentsCode: 'paymentsCode',
|
||||||
};
|
};
|
||||||
|
|
||||||
const icons = {
|
const icons = {
|
||||||
|
@ -35,6 +41,24 @@ const icons = {
|
||||||
ViewInFiat: {
|
ViewInFiat: {
|
||||||
iconValue: 'coloncurrencysign.circle',
|
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 = {
|
export const CommonToolTipActions = {
|
||||||
|
@ -78,7 +102,6 @@ export const CommonToolTipActions = {
|
||||||
text: loc.total_balance_view.view_in_fiat,
|
text: loc.total_balance_view.view_in_fiat,
|
||||||
icon: icons.ViewInFiat,
|
icon: icons.ViewInFiat,
|
||||||
},
|
},
|
||||||
|
|
||||||
ViewInSats: {
|
ViewInSats: {
|
||||||
id: keys.ViewInSats,
|
id: keys.ViewInSats,
|
||||||
text: loc.total_balance_view.view_in_sats,
|
text: loc.total_balance_view.view_in_sats,
|
||||||
|
@ -89,4 +112,39 @@ export const CommonToolTipActions = {
|
||||||
text: loc.total_balance_view.view_in_bitcoin,
|
text: loc.total_balance_view.view_in_bitcoin,
|
||||||
icon: icons.ViewInBitcoin,
|
icon: icons.ViewInBitcoin,
|
||||||
},
|
},
|
||||||
|
Entropy: {
|
||||||
|
id: keys.Entropy,
|
||||||
|
text: loc.wallets.add_entropy_provide,
|
||||||
|
icon: icons.Entropy,
|
||||||
|
menuState: false,
|
||||||
|
},
|
||||||
|
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,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Reference in a new issue