REF: Use actionsheet anchor property button ipad options

This commit is contained in:
marcosrdz 2021-02-26 19:23:59 -05:00
parent 6560131030
commit 555125f85e
13 changed files with 98 additions and 70 deletions

View File

@ -1,5 +1,5 @@
/* eslint react/prop-types: "off", react-native/no-inline-styles: "off" */
import React, { Component, useState, useMemo, useCallback, useContext, useRef } from 'react';
import React, { Component, useState, useMemo, useCallback, useContext, useRef, forwardRef } from 'react';
import PropTypes from 'prop-types';
import { Icon, Input, Text, Header, ListItem, Avatar } from 'react-native-elements';
import {
@ -7,6 +7,7 @@ import {
Alert,
Animated,
Dimensions,
findNodeHandle,
Image,
InputAccessoryView,
Keyboard,
@ -93,7 +94,7 @@ export const BlueButton = props => {
);
};
export const SecondButton = props => {
export const SecondButton = forwardRef((props, ref) => {
const { colors } = useTheme();
let backgroundColor = props.backgroundColor ? props.backgroundColor : colors.buttonBlueBackgroundColor;
let fontColor = colors.buttonTextColor;
@ -117,6 +118,7 @@ export const SecondButton = props => {
alignItems: 'center',
}}
{...props}
ref={ref}
>
<View style={{ flexDirection: 'row', justifyContent: 'center', alignItems: 'center' }}>
{props.icon && <Icon name={props.icon.name} type={props.icon.type} color={props.icon.color} />}
@ -124,7 +126,7 @@ export const SecondButton = props => {
</View>
</TouchableOpacity>
);
};
});
export const BitcoinButton = props => {
const { colors } = useTheme();
@ -453,7 +455,7 @@ export class BlueWalletNavigationHeader extends Component {
}
}
export const BlueButtonLink = props => {
export const BlueButtonLink = forwardRef((props, ref) => {
const { colors } = useTheme();
return (
<TouchableOpacity
@ -463,11 +465,12 @@ export const BlueButtonLink = props => {
justifyContent: 'center',
}}
{...props}
ref={ref}
>
<Text style={{ color: colors.foregroundColor, textAlign: 'center', fontSize: 16 }}>{props.title}</Text>
</TouchableOpacity>
);
};
});
export const BlueAlertWalletExportReminder = ({ onSuccess = () => {}, onFailure }) => {
Alert.alert(
@ -1562,6 +1565,7 @@ export const BlueAddressInput = ({
launchedBy,
}) => {
const { colors } = useTheme();
const scanButtonRef = useRef();
return (
<View
@ -1594,10 +1598,11 @@ export const BlueAddressInput = ({
<TouchableOpacity
testID="BlueAddressInputScanQrButton"
disabled={isLoading}
ref={scanButtonRef}
onPress={() => {
Keyboard.dismiss();
if (isDesktop) {
fs.showActionSheet().then(onBarScanned);
fs.showActionSheet({ anchor: findNodeHandle(scanButtonRef.current) }).then(onBarScanned);
} else {
NavigationService.navigate('ScanQRCodeRoot', {
screen: 'ScanQRCode',

View File

@ -193,7 +193,7 @@ const showFilePickerAndReadFile = async function () {
};
// Intended for macOS Catalina. Not for long press shortcut
const showActionSheet = async () => {
const showActionSheet = async props => {
const isClipboardEmpty = (await Clipboard.getString()).replace(' ', '').length === 0;
let copyFromClipboardIndex;
const options = [loc._.cancel, loc.wallets.take_photo, loc.wallets.list_long_choose];
@ -206,7 +206,7 @@ const showActionSheet = async () => {
const importFileButtonIndex = options.length - 1;
return new Promise(resolve =>
ActionSheet.showActionSheetWithOptions({ options, cancelButtonIndex: 0 }, async buttonIndex => {
ActionSheet.showActionSheetWithOptions({ options, cancelButtonIndex: 0, anchor: props.anchor }, async buttonIndex => {
if (buttonIndex === 1) {
takePhotoWithImagePickerAndReadPhoto().then(resolve);
} else if (buttonIndex === 2) {

View File

@ -1,4 +1,4 @@
import React, { useState, useRef } from 'react';
import React, { useState, useRef, forwardRef } from 'react';
import PropTypes from 'prop-types';
import { View, Text, TouchableOpacity, StyleSheet, Dimensions, PixelRatio } from 'react-native';
import { useTheme } from '@react-navigation/native';
@ -25,7 +25,7 @@ const cStyles = StyleSheet.create({
},
});
export const FContainer = ({ children }) => {
export const FContainer = forwardRef((props, ref) => {
const [newWidth, setNewWidth] = useState();
const layoutCalculated = useRef(false);
@ -34,7 +34,7 @@ export const FContainer = ({ children }) => {
const maxWidth = Dimensions.get('window').width - BORDER_RADIUS - 20;
const { width } = event.nativeEvent.layout;
const withPaddings = Math.ceil(width + PADDINGS * 2);
const len = React.Children.toArray(children).filter(Boolean).length;
const len = React.Children.toArray(props.children).filter(Boolean).length;
let newWidth = withPaddings * len > maxWidth ? Math.floor(maxWidth / len) : withPaddings;
if (len === 1 && newWidth < 90) newWidth = 90; // to add Paddings for lonely small button, like Scan on main screen
setNewWidth(newWidth);
@ -42,9 +42,9 @@ export const FContainer = ({ children }) => {
};
return (
<View onLayout={onLayout} style={[cStyles.root, newWidth ? cStyles.rootPost : cStyles.rootPre]}>
<View ref={ref} onLayout={onLayout} style={[cStyles.root, newWidth ? cStyles.rootPost : cStyles.rootPre]}>
{newWidth
? React.Children.toArray(children)
? React.Children.toArray(props.children)
.filter(Boolean)
.map((c, index, array) =>
React.cloneElement(c, {
@ -54,10 +54,10 @@ export const FContainer = ({ children }) => {
last: index === array.length - 1,
}),
)
: children}
: props.children}
</View>
);
};
});
FContainer.propTypes = {
children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.element), PropTypes.element]),

View File

@ -1,10 +1,10 @@
/* eslint react/prop-types: "off", react-native/no-inline-styles: "off" */
import React from 'react';
import React, { forwardRef } from 'react';
import { TouchableOpacity, View, Text } from 'react-native';
import { Icon } from 'react-native-elements';
import { useTheme } from '@react-navigation/native';
export const SquareButton = props => {
export const SquareButton = forwardRef((props, ref) => {
const { colors } = useTheme();
let backgroundColor = props.backgroundColor ? props.backgroundColor : colors.buttonBlueBackgroundColor;
let fontColor = colors.buttonTextColor;
@ -28,6 +28,7 @@ export const SquareButton = props => {
alignItems: 'center',
}}
{...props}
ref={ref}
>
<View style={{ flexDirection: 'row', justifyContent: 'center', alignItems: 'center' }}>
{props.icon && <Icon name={props.icon.name} type={props.icon.type} color={props.icon.color} />}
@ -35,4 +36,4 @@ export const SquareButton = props => {
</View>
</TouchableOpacity>
);
};
});

View File

@ -346,7 +346,7 @@ const WalletsCarousel = forwardRef((props, ref) => {
WalletsCarousel.propTypes = {
vertical: PropTypes.bool,
selectedWallet: PropTypes.object,
selectedWallet: PropTypes.string,
onPress: PropTypes.func.isRequired,
handleLongPress: PropTypes.func.isRequired,
};

View File

@ -1,6 +1,6 @@
import React, { useState, useContext } from 'react';
import React, { useState, useContext, useRef } from 'react';
import { useNavigation, useRoute, useTheme } from '@react-navigation/native';
import { StyleSheet, View, KeyboardAvoidingView, Platform, TextInput, Keyboard } from 'react-native';
import { StyleSheet, View, KeyboardAvoidingView, Platform, TextInput, Keyboard, findNodeHandle } from 'react-native';
import loc from '../../loc';
import { BlueButton, BlueButtonLink, BlueCard, BlueSpacing10, BlueSpacing20, BlueText, SafeBlueArea } from '../../BlueComponents';
@ -15,6 +15,7 @@ const IsItMyAddress = () => {
const { navigate } = useNavigation();
const { name } = useRoute();
const { colors } = useTheme();
const scanButtonRef = useRef();
const [address, setAddress] = useState('');
const [result, setResult] = useState('');
@ -58,7 +59,7 @@ const IsItMyAddress = () => {
const importScan = () => {
if (isMacCatalina) {
fs.showActionSheet().then(onBarScanned);
fs.showActionSheet({ anchor: findNodeHandle(scanButtonRef.current) }).then(onBarScanned);
} else {
navigate('ScanQRCodeRoot', {
screen: 'ScanQRCode',
@ -102,7 +103,7 @@ const IsItMyAddress = () => {
</View>
<BlueSpacing10 />
<BlueButtonLink title={loc.wallets.import_scan_qr} onPress={importScan} />
<BlueButtonLink ref={scanButtonRef} title={loc.wallets.import_scan_qr} onPress={importScan} />
<BlueSpacing10 />
<BlueButton title={loc.send.input_clear} onPress={clearAddressInput} />
<BlueSpacing20 />

View File

@ -1,6 +1,6 @@
/* global alert */
import React, { useState } from 'react';
import { ActivityIndicator, ScrollView, StyleSheet, View } from 'react-native';
import React, { useRef, useState } from 'react';
import { ActivityIndicator, findNodeHandle, ScrollView, StyleSheet, View } from 'react-native';
import { getSystemName } from 'react-native-device-info';
import { useNavigation, useRoute, useTheme } from '@react-navigation/native';
@ -17,6 +17,7 @@ const isDesktop = getSystemName() === 'Mac OS X';
const PsbtMultisigQRCode = () => {
const { navigate } = useNavigation();
const { colors } = useTheme();
const openScannerButton = useRef();
const { psbtBase64, isShowOpenScanner } = useRoute().params;
const [isLoading, setIsLoading] = useState(false);
@ -50,7 +51,7 @@ const PsbtMultisigQRCode = () => {
const openScanner = () => {
if (isDesktop) {
fs.showActionSheet().then(data => onBarScanned({ data }));
fs.showActionSheet({ anchor: findNodeHandle(openScannerButton.current) }).then(data => onBarScanned({ data }));
} else {
navigate('ScanQRCodeRoot', {
screen: 'ScanQRCode',
@ -79,6 +80,7 @@ const PsbtMultisigQRCode = () => {
testID="CosignedScanOrImportFile"
style={[styles.exportButton, stylesHook.exportButton]}
onPress={openScanner}
ref={openScannerButton}
title={loc.multisig.scan_or_import_file}
/>
</>

View File

@ -12,6 +12,7 @@ import {
Text,
StyleSheet,
Alert,
findNodeHandle,
} from 'react-native';
import Clipboard from '@react-native-community/clipboard';
import Share from 'react-native-share';
@ -50,6 +51,7 @@ const PsbtWithHardwareWallet = () => {
const { colors } = useTheme();
const [isLoading, setIsLoading] = useState(false);
const [txHex, setTxHex] = useState(route.params.txhex);
const openScannerButton = useRef();
const stylesHook = StyleSheet.create({
root: {
@ -250,7 +252,7 @@ const PsbtWithHardwareWallet = () => {
const openScanner = () => {
if (isMacCatalina) {
fs.showActionSheet().then(data => onBarScanned({ data }));
fs.showActionSheet({ anchor: findNodeHandle(openScannerButton.current) }).then(data => onBarScanned({ data }));
} else {
navigation.navigate('ScanQRCodeRoot', {
screen: 'ScanQRCode',
@ -289,6 +291,7 @@ const PsbtWithHardwareWallet = () => {
color: colors.buttonTextColor,
}}
onPress={openScanner}
ref={openScannerButton}
title={loc.send.psbt_tx_scan}
/>
<BlueSpacing20 />

View File

@ -13,6 +13,7 @@ import {
TouchableOpacity,
View,
Alert,
findNodeHandle,
} from 'react-native';
import { Icon } from 'react-native-elements';
import { useNavigation, useRoute, useTheme } from '@react-navigation/native';
@ -66,6 +67,7 @@ const WalletsAddMultisigStep2 = () => {
const [vaultKeyData, setVaultKeyData] = useState({ keyIndex: 1, xpub: '', seed: '', isLoading: false }); // string rendered in modal
const [importText, setImportText] = useState('');
const tooltip = useRef();
const openScannerButton = useRef();
const data = useRef(new Array(n));
const hasUnsavedChanges = Boolean(cosigners.length > 0 && cosigners.length !== n);
@ -428,7 +430,7 @@ const WalletsAddMultisigStep2 = () => {
const scanOrOpenFile = () => {
if (isDesktop) {
fs.showActionSheet().then(onBarScanned);
fs.showActionSheet({ anchor: findNodeHandle(openScannerButton.current) }).then(onBarScanned);
} else {
setIsProvideMnemonicsModalVisible(false);
navigation.navigate('ScanQRCodeRoot', {
@ -614,7 +616,7 @@ const WalletsAddMultisigStep2 = () => {
) : (
<BlueButton disabled={importText.trim().length === 0} title={loc.wallets.import_do_import} onPress={useMnemonicPhrase} />
)}
<BlueButtonLink disabled={isLoading} onPress={scanOrOpenFile} title={loc.wallets.import_scan_qr} />
<BlueButtonLink ref={openScannerButton} disabled={isLoading} onPress={scanOrOpenFile} title={loc.wallets.import_scan_qr} />
</View>
</KeyboardAvoidingView>
</BottomModal>

View File

@ -164,7 +164,9 @@ const WalletDetails = () => {
}, []);
useEffect(() => {
if (wallets.some(wallet => wallet.getID() === walletID)) {
setSelectedWallet(walletID);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [walletID]);

View File

@ -12,6 +12,7 @@ import {
Dimensions,
useWindowDimensions,
SafeAreaView,
findNodeHandle,
} from 'react-native';
import { BlueHeaderDefaultMain, BlueTransactionListItem } from '../../BlueComponents';
import WalletsCarousel from '../../components/WalletsCarousel';
@ -50,6 +51,7 @@ const WalletsList = () => {
const [carouselData, setCarouselData] = useState([]);
const dataSource = getTransactions(null, 10);
const walletsCount = useRef(wallets.length);
const walletActionButtonsRef = useRef();
const stylesHook = StyleSheet.create({
walletsListWrapper: {
@ -318,7 +320,7 @@ const WalletsList = () => {
const renderScanButton = () => {
if (carouselData.length > 0 && !carouselData.some(wallet => wallet.type === PlaceholderWallet.type)) {
return (
<FContainer>
<FContainer ref={walletActionButtonsRef}>
<FButton
onPress={onScanButtonPressed}
onLongPress={isMacCatalina ? undefined : sendButtonLongPress}
@ -338,7 +340,7 @@ const WalletsList = () => {
const onScanButtonPressed = () => {
if (isMacCatalina) {
fs.showActionSheet().then(onBarScanned);
fs.showActionSheet({ anchor: walletActionButtonsRef.current }).then(onBarScanned);
} else {
navigate('ScanQRCodeRoot', {
screen: 'ScanQRCode',
@ -366,13 +368,15 @@ const WalletsList = () => {
const isClipboardEmpty = (await Clipboard.getString()).replace(' ', '').length === 0;
if (Platform.OS === 'ios') {
if (isMacCatalina) {
fs.showActionSheet().then(onBarScanned);
fs.showActionSheet({ anchor: findNodeHandle(walletActionButtonsRef.current) }).then(onBarScanned);
} else {
const options = [loc._.cancel, loc.wallets.list_long_choose, loc.wallets.list_long_scan];
if (!isClipboardEmpty) {
options.push(loc.wallets.list_long_clipboard);
}
ActionSheet.showActionSheetWithOptions({ options, cancelButtonIndex: 0 }, buttonIndex => {
ActionSheet.showActionSheetWithOptions(
{ options, cancelButtonIndex: 0, anchor: findNodeHandle(walletActionButtonsRef.current) },
buttonIndex => {
if (buttonIndex === 1) {
fs.showImagePickerAndReadImage().then(onBarScanned);
} else if (buttonIndex === 2) {
@ -387,7 +391,8 @@ const WalletsList = () => {
} else if (buttonIndex === 3) {
copyFromClipboard();
}
});
},
);
}
} else if (Platform.OS === 'android') {
const buttons = [

View File

@ -1,5 +1,5 @@
/* global alert */
import React, { useEffect, useState, useCallback, useContext } from 'react';
import React, { useEffect, useState, useCallback, useContext, useRef } from 'react';
import {
ActivityIndicator,
Alert,
@ -15,6 +15,7 @@ import {
StatusBar,
StyleSheet,
Text,
findNodeHandle,
TouchableOpacity,
View,
} from 'react-native';
@ -58,6 +59,7 @@ const WalletTransactions = () => {
const [pageSize, setPageSize] = useState(20);
const { setParams, setOptions, navigate } = useNavigation();
const { colors } = useTheme();
const walletActionButtonsRef = useRef();
const stylesHook = StyleSheet.create({
advancedTransactionOptionsModalContent: {
@ -513,7 +515,7 @@ const WalletTransactions = () => {
const sendButtonLongPress = async () => {
if (isMacCatalina) {
fs.showActionSheet().then(onBarCodeRead);
fs.showActionSheet({ anchor: walletActionButtonsRef.current }).then(onBarCodeRead);
} else {
const isClipboardEmpty = (await Clipboard.getString()).replace(' ', '').length === 0;
if (Platform.OS === 'ios') {
@ -521,7 +523,9 @@ const WalletTransactions = () => {
if (!isClipboardEmpty) {
options.push(loc.wallets.list_long_clipboard);
}
ActionSheet.showActionSheetWithOptions({ options, cancelButtonIndex: 0 }, buttonIndex => {
ActionSheet.showActionSheetWithOptions(
{ options, cancelButtonIndex: 0, anchor: findNodeHandle(walletActionButtonsRef.current) },
buttonIndex => {
if (buttonIndex === 1) {
choosePhoto();
} else if (buttonIndex === 2) {
@ -536,7 +540,8 @@ const WalletTransactions = () => {
} else if (buttonIndex === 3) {
copyFromClipboard();
}
});
},
);
} else if (Platform.OS === 'android') {
const buttons = [
{
@ -673,7 +678,7 @@ const WalletTransactions = () => {
{renderManageFundsModal()}
</View>
<FContainer>
<FContainer ref={walletActionButtonsRef}>
{wallet.allowReceive() && (
<FButton
testID="ReceiveButton"

View File

@ -3,6 +3,7 @@ import React, { useContext, useRef, useState, useCallback, useEffect } from 'rea
import {
ActivityIndicator,
Alert,
findNodeHandle,
FlatList,
InteractionManager,
Keyboard,
@ -49,6 +50,7 @@ const ViewEditMultisigCosigners = () => {
const { wallets, setWalletsWithNewOrder, setIsDrawerListBlurred } = useContext(BlueStorageContext);
const { navigate, dispatch, goBack, addListener } = useNavigation();
const route = useRoute();
const openScannerButtonRef = useRef();
const { walletId } = route.params;
const w = useRef(wallets.find(wallet => wallet.getID() === walletId));
const tempWallet = useRef(new MultisigHDWallet());
@ -473,7 +475,7 @@ const ViewEditMultisigCosigners = () => {
const scanOrOpenFile = () => {
if (isMacCatalina) {
fs.showActionSheet().then(result => {
fs.showActionSheet({ anchor: findNodeHandle(openScannerButtonRef.current) }).then(result => {
// Triggers FlatList re-render
setImportText(result);
//
@ -525,7 +527,7 @@ const ViewEditMultisigCosigners = () => {
onPress={handleUseMnemonicPhrase}
/>
)}
<BlueButtonLink disabled={isLoading} onPress={scanOrOpenFile} title={loc.wallets.import_scan_qr} />
<BlueButtonLink ref={openScannerButtonRef} disabled={isLoading} onPress={scanOrOpenFile} title={loc.wallets.import_scan_qr} />
</View>
</KeyboardAvoidingView>
</BottomModal>