mirror of
https://github.com/minibits-cash/minibits_wallet.git
synced 2026-10-05 19:28:26 +00:00
add share by qr code
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { observer } from "mobx-react-lite"
|
||||
import React from "react"
|
||||
import { ColorValue, Image, TextStyle, View, ViewStyle } from "react-native"
|
||||
import { ColorValue, Image, Pressable, TextStyle, View, ViewStyle } from "react-native"
|
||||
import { Icon, Text } from "."
|
||||
import { spacing, useThemeColor } from "../theme"
|
||||
import { getImageSource } from '../utils/utils'
|
||||
@@ -10,6 +10,10 @@ import { iconRegistry } from '.'
|
||||
export interface AvatarHeaderProps {
|
||||
heading?: string,
|
||||
text?: string,
|
||||
/** will have no effect if text is falsy */
|
||||
onTextPress?: () => void,
|
||||
/** will have no effect if text is falsy */
|
||||
onTextLongPress?: () => void,
|
||||
picture?: string
|
||||
/** default is 96 for pic, 48 for icon - another option is 90 or 80 */
|
||||
pictureHeight?: number,
|
||||
@@ -58,7 +62,9 @@ export const AvatarHeader = observer(function (props: AvatarHeaderProps) {
|
||||
)}
|
||||
</View>
|
||||
{props.heading && <Text style={{ fontSize: 26, lineHeight: 40 }} text={props.heading} adjustsFontSizeToFit={true} numberOfLines={1} />}
|
||||
{props.text && <Text preset='bold' text={props.text} style={{ color: 'white', marginBottom: spacing.small }} numberOfLines={2} />}
|
||||
{props.text && <Pressable onPress={props.onTextPress} onLongPress={props.onTextLongPress}>
|
||||
<Text preset='bold' text={props.text} style={{ color: 'white', marginBottom: spacing.small }} numberOfLines={2} />
|
||||
</Pressable>}
|
||||
{props.children}
|
||||
</View>
|
||||
)
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
import React, { useState } from 'react'
|
||||
import { View } from 'react-native'
|
||||
import type { TextStyle } from 'react-native';
|
||||
|
||||
import { BottomModal } from './BottomModal';
|
||||
import { Text } from './Text';
|
||||
import { QRCodeBlock, QRCodeBlockTypes } from '../screens/Wallet/QRCode';
|
||||
import { spacing, useThemeColor } from '../theme';
|
||||
import { translate, TxKeyPath } from '../i18n';
|
||||
|
||||
interface QRShareModalProps {
|
||||
url: string,
|
||||
isVisible?: boolean,
|
||||
onClose?: () => void,
|
||||
type: QRCodeBlockTypes
|
||||
shareModalTitle?: string,
|
||||
shareModalTx?: TxKeyPath,
|
||||
subHeading?: string,
|
||||
label?: string
|
||||
labelTx?: TxKeyPath,
|
||||
size?: number,
|
||||
}
|
||||
|
||||
export const QRShareModal = (props: QRShareModalProps) => {
|
||||
const labelText = useThemeColor('textDim')
|
||||
const {
|
||||
url,
|
||||
isVisible = true,
|
||||
onClose = () => {},
|
||||
shareModalTitle,
|
||||
shareModalTx,
|
||||
subHeading,
|
||||
type,
|
||||
label,
|
||||
labelTx,
|
||||
size
|
||||
} = props
|
||||
|
||||
let finalTx: TxKeyPath | undefined = shareModalTx
|
||||
if (!shareModalTx && !shareModalTitle) finalTx = 'common.share'
|
||||
|
||||
return (
|
||||
<BottomModal
|
||||
isVisible={isVisible}
|
||||
ContentComponent={
|
||||
<>
|
||||
<Text
|
||||
tx={finalTx}
|
||||
text={shareModalTitle}
|
||||
preset="subheading"
|
||||
style={{alignSelf: 'center', marginBottom: spacing.small}}
|
||||
/>
|
||||
<View style={$newContainer}>
|
||||
<QRCodeBlock
|
||||
qrCodeData={url.toString()}
|
||||
title={subHeading || shareModalTitle || translate('common.share')}
|
||||
type={type}
|
||||
size={size}
|
||||
/>
|
||||
{(label || labelTx) &&
|
||||
<Text
|
||||
size="xxs"
|
||||
style={{
|
||||
color: labelText,
|
||||
marginTop: spacing.medium,
|
||||
alignSelf: 'center',
|
||||
}}
|
||||
text={label}
|
||||
tx={labelTx && !label ? labelTx : undefined}
|
||||
/>
|
||||
}
|
||||
</View>
|
||||
</>
|
||||
}
|
||||
onBackButtonPress={onClose}
|
||||
onBackdropPress={onClose}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
const $newContainer: TextStyle = {
|
||||
alignSelf: 'stretch',
|
||||
}
|
||||
@@ -33,6 +33,7 @@ import AppError, { Err } from '../utils/AppError'
|
||||
import { useHeader } from '../utils/useHeader'
|
||||
import { CurrencySign } from './Wallet/CurrencySign'
|
||||
import { SvgXml } from 'react-native-svg'
|
||||
import { QRShareModal } from '../components/QRShareModal'
|
||||
|
||||
|
||||
if (Platform.OS === 'android' && UIManager.setLayoutAnimationEnabledExperimental) {
|
||||
@@ -368,6 +369,7 @@ export const MintInfoScreen: FC<SettingsStackScreenProps<'MintInfo'>> = observer
|
||||
const [mintInfo, setMintInfo] = useState<GetInfoResponse | undefined>()
|
||||
const [mint, setMint] = useState<Mint>()
|
||||
const [isLocalInfoVisible, setIsLocalInfoVisible] = useState<boolean>(false)
|
||||
const [shareModalVisible, setShareModalVisible] = useState(false)
|
||||
|
||||
const [error, setError] = useState<AppError | undefined>()
|
||||
const [info, setInfo] = useState('')
|
||||
@@ -415,6 +417,9 @@ export const MintInfoScreen: FC<SettingsStackScreenProps<'MintInfo'>> = observer
|
||||
setIsLocalInfoVisible(!isLocalInfoVisible)
|
||||
}
|
||||
|
||||
const openShareModal = () => { setShareModalVisible(true) }
|
||||
const closeShareModal = () => { setShareModalVisible(false) }
|
||||
|
||||
const handleError = function (e: AppError): void {
|
||||
setIsLoading(false)
|
||||
setError(e)
|
||||
@@ -442,7 +447,10 @@ export const MintInfoScreen: FC<SettingsStackScreenProps<'MintInfo'>> = observer
|
||||
}
|
||||
headerHeightModifier={0.26}
|
||||
heading={mintInfo?.name ?? translate('mintInfo.loadingNamePlaceholder')}
|
||||
text={route.params.mintUrl}>
|
||||
text={route.params.mintUrl}
|
||||
onTextPress={openShareModal}
|
||||
onTextLongPress={openShareModal}
|
||||
>
|
||||
{mint?.units ? (
|
||||
<View style={{flexDirection: 'row'}}>
|
||||
{mint.units.map(unit => (
|
||||
@@ -515,6 +523,14 @@ export const MintInfoScreen: FC<SettingsStackScreenProps<'MintInfo'>> = observer
|
||||
</>
|
||||
}
|
||||
/>
|
||||
<QRShareModal
|
||||
url={route.params.mintUrl}
|
||||
shareModalTx='mintsScreen.share'
|
||||
subHeading={mintInfo?.name ?? translate('mintInfo.loadingNamePlaceholder')}
|
||||
type='URL'
|
||||
isVisible={shareModalVisible}
|
||||
onClose={closeShareModal}
|
||||
/>
|
||||
{error && <ErrorModal error={error} />}
|
||||
{info && <InfoModal message={info} />}
|
||||
</View>
|
||||
|
||||
+28
-29
@@ -31,8 +31,7 @@ import { SvgXml } from 'react-native-svg'
|
||||
import { isStateTreeNode } from 'mobx-state-tree'
|
||||
import { MintKeyset } from '@cashu/cashu-ts'
|
||||
import { QRCodeBlock } from './Wallet/QRCode'
|
||||
|
||||
|
||||
import { QRShareModal } from '../components/QRShareModal'
|
||||
|
||||
export const MintsScreen: FC<SettingsStackScreenProps<'Mints'>> = observer(function MintsScreen({route, navigation}) {
|
||||
useHeader({
|
||||
@@ -47,11 +46,12 @@ export const MintsScreen: FC<SettingsStackScreenProps<'Mints'>> = observer(funct
|
||||
const [mintUrl, setMintUrl] = useState('')
|
||||
const [defaultMintUrl, setDefaultMintUrl] = useState<string>(MINIBITS_MINT_URL)
|
||||
const [selectedMint, setSelectedMint] = useState<Mint | undefined>()
|
||||
const [sharingMint, setSharingMint] = useState<string | undefined>()
|
||||
const [lastSelectedMint, setLastSelectedMint] = useState<Mint | undefined>()
|
||||
const [info, setInfo] = useState('')
|
||||
const [error, setError] = useState<AppError | undefined>()
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
const [isAddMintVisible, setIsAddMintVisible] = useState(false)
|
||||
const [shareModalVisible, setShareModalVisible] = useState(false)
|
||||
|
||||
|
||||
const toggleAddMintModal = async function () {
|
||||
@@ -75,15 +75,15 @@ export const MintsScreen: FC<SettingsStackScreenProps<'Mints'>> = observer(funct
|
||||
|
||||
|
||||
const gotoScan = function () {
|
||||
toggleAddMintModal()
|
||||
navigation.navigate('WalletNavigator', {screen: 'Scan'})
|
||||
toggleAddMintModal()
|
||||
navigation.navigate('WalletNavigator', {screen: 'Scan'})
|
||||
}
|
||||
|
||||
|
||||
const gotoInfo = function () {
|
||||
if(!selectedMint) {return}
|
||||
navigation.navigate('MintInfo', {mintUrl: selectedMint?.mintUrl})
|
||||
onMintUnselect()
|
||||
if(!selectedMint) {return}
|
||||
navigation.navigate('MintInfo', {mintUrl: selectedMint?.mintUrl})
|
||||
onMintUnselect()
|
||||
}
|
||||
|
||||
|
||||
@@ -247,20 +247,22 @@ export const MintsScreen: FC<SettingsStackScreenProps<'Mints'>> = observer(funct
|
||||
}
|
||||
}
|
||||
|
||||
const shareMint = function () {
|
||||
// setSelectedMint(void 0)
|
||||
setSharingMint(selectedMint?.mintUrl)
|
||||
}
|
||||
|
||||
|
||||
const onMintSelect = function (mint: Mint) {
|
||||
setSelectedMint(mint)
|
||||
setLastSelectedMint(mint)
|
||||
}
|
||||
|
||||
const onMintUnselect = function () {
|
||||
setSelectedMint(undefined)
|
||||
}
|
||||
|
||||
const openShareModal = () => {
|
||||
setSelectedMint(void 0)
|
||||
setShareModalVisible(true)
|
||||
}
|
||||
const closeShareModal = () => { setShareModalVisible(false) }
|
||||
|
||||
const handleError = function (e: AppError) {
|
||||
setIsLoading(false)
|
||||
setError(e)
|
||||
@@ -379,7 +381,7 @@ export const MintsScreen: FC<SettingsStackScreenProps<'Mints'>> = observer(funct
|
||||
/>*/}
|
||||
<ListItem
|
||||
leftIcon="faShareNodes"
|
||||
onPress={shareMint}
|
||||
onPress={openShareModal}
|
||||
tx="mintsScreen.share"
|
||||
bottomSeparator={true}
|
||||
style={{paddingHorizontal: spacing.medium}}
|
||||
@@ -389,7 +391,7 @@ export const MintsScreen: FC<SettingsStackScreenProps<'Mints'>> = observer(funct
|
||||
onPress={onCopyMintUrl}
|
||||
tx='mintsScreen.copy'
|
||||
bottomSeparator={true}
|
||||
style={{paddingHorizontal: spacing.medium}}
|
||||
style={{paddingHorizontal: spacing.medium}}j
|
||||
/>
|
||||
<ListItem
|
||||
leftIcon='faGlobe'
|
||||
@@ -487,20 +489,17 @@ export const MintsScreen: FC<SettingsStackScreenProps<'Mints'>> = observer(funct
|
||||
onBackButtonPress={toggleAddMintModal}
|
||||
onBackdropPress={toggleAddMintModal}
|
||||
/>
|
||||
{/* TODO fix */}
|
||||
<BottomModal
|
||||
isVisible={sharingMint && selectedMint ? true : false}
|
||||
ContentComponent={
|
||||
<>
|
||||
<QRCodeBlock
|
||||
qrCodeData={sharingMint || ''}
|
||||
title='Share Mint URL'
|
||||
type='URL'
|
||||
/>
|
||||
<Button preset='secondary' onPress={() => setSharingMint(void 0)} text='Close' />
|
||||
</>
|
||||
}
|
||||
/>
|
||||
{/* using lastSelectedMint so we can close the underlying modal */}
|
||||
{lastSelectedMint && typeof lastSelectedMint?.mintUrl === 'string' &&
|
||||
<QRShareModal
|
||||
url={lastSelectedMint?.mintUrl as string}
|
||||
shareModalTx='mintsScreen.share'
|
||||
subHeading={lastSelectedMint?.shortname as string}
|
||||
type='URL'
|
||||
isVisible={shareModalVisible}
|
||||
onClose={closeShareModal}
|
||||
/>
|
||||
}
|
||||
{error && <ErrorModal error={error} />}
|
||||
{info && <InfoModal message={info} />}
|
||||
</Screen>
|
||||
|
||||
@@ -11,11 +11,11 @@ import { translate } from "../../i18n"
|
||||
import { CashuUtils, TokenV3 } from "../../services/cashu/cashuUtils"
|
||||
import { log } from "../../services"
|
||||
|
||||
|
||||
export type QRCodeBlockTypes = 'EncodedV3Token' | 'EncodedV4Token' | 'Bolt11Invoice' | 'URL' | 'NWC'
|
||||
export const QRCodeBlock = function (props: {
|
||||
qrCodeData: string
|
||||
title: string
|
||||
type: 'EncodedV3Token' | 'EncodedV4Token' | 'Bolt11Invoice' | 'URL' | 'NWC'
|
||||
type: QRCodeBlockTypes
|
||||
size?: number
|
||||
}
|
||||
) {
|
||||
|
||||
Reference in New Issue
Block a user