feat: QR: Share: add ability to select share QR or share text

This commit is contained in:
Evan Kaloudis
2025-06-23 19:55:39 -04:00
parent 717b15e5d7
commit fdabfcd83a
6 changed files with 209 additions and 3 deletions
+3
View File
@@ -42,6 +42,7 @@ import AlertModal from './components/Modals/AlertModal';
import ExternalLinkModal from './components/Modals/ExternalLinkModal';
import AndroidNfcModal from './components/Modals/AndroidNfcModal';
import InfoModal from './components/Modals/InfoModal';
import ShareModal from './components/Modals/ShareModal';
// Views
import Transaction from './views/Transaction';
@@ -1170,6 +1171,8 @@ export default class App extends React.PureComponent {
<AndroidNfcModal />
{/* @ts-ignore:next-line */}
<InfoModal />
{/* @ts-ignore:next-line */}
<ShareModal />
</GestureHandlerRootView>
</PushNotificationManager>
</AppContainer>
+4
View File
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<svg width="800px" height="800px" viewBox="0 0 16 16" fill="#000" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M15 1H1V15H15V1ZM3 3V7H5V5H7V11H5V13H11V11H9V5H11V7H13V3H3Z" fill="#000"/>
</svg>

After

Width:  |  Height:  |  Size: 273 B

+147
View File
@@ -0,0 +1,147 @@
import React from 'react';
import { View, StyleSheet, TouchableOpacity } from 'react-native';
import { inject, observer } from 'mobx-react';
import Text from '../../components/Text';
import { Row } from '../../components/layout/Row';
import ModalBox from '../ModalBox';
import ModalStore from '../../stores/ModalStore';
import { localeString } from '../../utils/LocaleUtils';
import { themeColor } from '../../utils/ThemeUtils';
import QR from '../../assets/images/SVG/QR.svg';
import TextSVG from '../../assets/images/SVG/Text.svg';
interface ShareModalProps {
ModalStore: ModalStore;
}
@inject('ModalStore')
@observer
export default class ShareModal extends React.Component<ShareModalProps, {}> {
render() {
const { ModalStore } = this.props;
const {
showShareModal,
toggleShareModal,
shareQR,
shareText,
closeVisibleModalDialog
} = ModalStore;
return (
<ModalBox
style={{
...styles.modal,
backgroundColor: themeColor('background')
}}
swipeToClose={true}
backButtonClose={true}
backdropPressToClose={true}
backdrop={true}
position="bottom"
isOpen={showShareModal}
onClosed={() => toggleShareModal({})}
>
<View>
<Text
style={{
fontFamily: 'PPNeueMontreal-Book',
color: themeColor('text'),
fontSize: 16,
paddingTop: 24,
paddingBottom: 24
}}
>
{localeString('general.share')}
</Text>
<TouchableOpacity
key="share-qr"
onPress={async () => {
shareQR();
closeVisibleModalDialog();
}}
style={{
...styles.sendOption,
backgroundColor: themeColor('secondary')
}}
>
<Row>
<View style={{ marginRight: 15 }}>
<QR
fill={
themeColor('action') ||
themeColor('highlight')
}
width={30}
height={30}
/>
</View>
<Text
style={{
...styles.sendOptionLabel,
color: themeColor('text')
}}
>
{localeString('general.qr')}
</Text>
</Row>
</TouchableOpacity>
<TouchableOpacity
key="share-text"
onPress={async () => {
shareText();
closeVisibleModalDialog();
}}
style={{
...styles.sendOption,
backgroundColor: themeColor('secondary')
}}
>
<Row>
<View style={{ marginRight: 15 }}>
<TextSVG
fill={
themeColor('action') ||
themeColor('highlight')
}
width={30}
height={30}
/>
</View>
<Text
style={{
...styles.sendOptionLabel,
color: themeColor('text')
}}
>
{localeString('general.text')}
</Text>
</Row>
</TouchableOpacity>
</View>
</ModalBox>
);
}
}
const styles = StyleSheet.create({
modal: {
borderTopLeftRadius: 20,
borderTopRightRadius: 20,
height: 250,
paddingLeft: 24,
paddingRight: 24
},
sendOption: {
borderRadius: 5,
padding: 16,
marginBottom: 24
},
sendOptionLabel: {
fontFamily: 'PPNeueMontreal-Book',
fontSize: 22
}
});
+22 -3
View File
@@ -6,12 +6,14 @@ import { captureRef } from 'react-native-view-shot';
import Share from 'react-native-share';
import { Icon } from 'react-native-elements';
import Button from './../components/Button';
import Button from '../components/Button';
import { localeString } from '../utils/LocaleUtils';
import { sleep } from '../utils/SleepUtils';
import { themeColor } from '../utils/ThemeUtils';
import { modalStore } from '../stores/Stores';
type QRCodeElement = React.ElementRef<typeof QRCode>;
interface ShareButtonProps {
@@ -30,10 +32,13 @@ export default class ShareButton extends React.Component<ShareButtonProps> {
handlePress = async () => {
const { onPress } = this.props;
await onPress();
await this.shareContent();
modalStore.toggleShareModal({
onShareQR: this.shareQR,
onShareText: this.shareText
});
};
shareContent = async () => {
shareQR = async () => {
const { value, qrRef, onShareComplete } = this.props;
try {
if (!qrRef?.current) return;
@@ -56,6 +61,20 @@ export default class ShareButton extends React.Component<ShareButtonProps> {
}
};
shareText = async () => {
const { value, onShareComplete } = this.props;
try {
await Share.open({
message: value
});
} catch (error) {
// Share API throws error when share sheet closes, regardless of success
console.log('Error in shareContent:', error);
} finally {
onShareComplete?.();
}
};
render() {
const { title, icon, noUppercase, iconOnly, iconContainerStyle } =
this.props;
+2
View File
@@ -152,6 +152,8 @@
"general.min": "Min",
"general.max": "Max",
"general.encrypt": "Encrypt",
"general.qr": "QR",
"general.text": "Text",
"channel.status.good": "Good",
"channel.status.stable": "Stable",
"channel.status.unstable": "Unstable",
+31
View File
@@ -5,6 +5,7 @@ export default class ModalStore {
@observable public showAndroidNfcModal: boolean = false;
@observable public showInfoModal: boolean = false;
@observable public showAlertModal: boolean = false;
@observable public showShareModal: boolean = false;
@observable public modalUrl: string;
@observable public clipboardValue: string;
@observable public infoModalTitle: string | undefined;
@@ -17,6 +18,8 @@ export default class ModalStore {
@observable public alertModalText: string | Array<string> | undefined;
@observable public alertModalLink: string | undefined;
@observable public alertModalNav: string | undefined;
@observable public onShareQR?: () => void;
@observable public onShareText?: () => void;
@observable public onPress: () => void;
/* External Link Modal */
@@ -49,6 +52,28 @@ export default class ModalStore {
this.showAlertModal = status;
};
@action
public toggleShareModal = ({
onShareQR,
onShareText
}: {
onShareQR?: () => void;
onShareText?: () => void;
}) => {
this.showShareModal = onShareQR && onShareText ? true : false;
this.onShareQR = onShareQR;
this.onShareText = onShareText;
};
@action
@action
public shareQR = () => {
if (this.onShareQR) this.onShareQR();
};
public shareText = () => {
if (this.onShareText) this.onShareText();
};
@action
public setUrl = (text: string) => {
this.modalUrl = text;
@@ -88,6 +113,12 @@ export default class ModalStore {
this.infoModalAdditionalButtons = undefined;
return true;
}
if (this.showShareModal) {
this.showShareModal = false;
this.onShareQR = undefined;
this.onShareText = undefined;
return true;
}
return false;
};
}