mirror of
https://github.com/minibits-cash/minibits_wallet.git
synced 2026-07-22 07:48:28 +00:00
Fix error and info modal on Android
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -5,7 +5,7 @@ minibits-upload-key.keystore
|
||||
GoogleService-Info.plist
|
||||
minibits-prod-firebase-adminsdk.json
|
||||
dist/
|
||||
zapstore
|
||||
zsp
|
||||
|
||||
# OSX
|
||||
#
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
shouldAutocreateTestPlan = "YES">
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Release"
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "minibits_wallet",
|
||||
"version": "0.4.0-beta.2",
|
||||
"version": "0.4.0-beta.3",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"android:clean": "cd android && ./gradlew clean",
|
||||
|
||||
@@ -59,7 +59,7 @@ export const AmountInput = forwardRef<TextInput, AmountInputProps>(
|
||||
const [hasBottomAmountFocusedOnce, setHasBottomAmountFocusedOnce] = useState(false)
|
||||
const [hasBeenFirstTimeConverted, setHasBeenFirstTimeConverted] = useState<boolean>(false)
|
||||
|
||||
const amountInputColor = useThemeColor("amountInput")
|
||||
const focusedInputColor = useThemeColor("amountInput")
|
||||
const convertedAmountColor = useThemeColor("headerSubTitle")
|
||||
const symbolColor = useThemeColor("headerSubTitle")
|
||||
|
||||
@@ -220,7 +220,7 @@ export const AmountInput = forwardRef<TextInput, AmountInputProps>(
|
||||
fontFamily: typography.primary?.bold,
|
||||
fontWeight: 'bold', // android
|
||||
textAlign: "center",
|
||||
color: amountInputColor,
|
||||
color: focusedInputColor,
|
||||
}
|
||||
|
||||
const animatedTopStyle = useAnimatedStyle(() => ({
|
||||
@@ -273,7 +273,12 @@ export const AmountInput = forwardRef<TextInput, AmountInputProps>(
|
||||
onEndEditing={onAmountEndEditing}
|
||||
onFocus={handleTopFocus}
|
||||
onBlur={handleTopBlur}
|
||||
style={[defaultTopStyle, style, animatedTopStyle]}
|
||||
style={[
|
||||
defaultTopStyle,
|
||||
style,
|
||||
animatedTopStyle,
|
||||
{ color: focused === 'top' ? focusedInputColor : convertedAmountColor }
|
||||
]}
|
||||
maxLength={9}
|
||||
keyboardType="decimal-pad"
|
||||
returnKeyType="done"
|
||||
@@ -307,6 +312,7 @@ export const AmountInput = forwardRef<TextInput, AmountInputProps>(
|
||||
style,
|
||||
{ color: convertedAmountColor },
|
||||
animatedBottomStyle,
|
||||
{ color: focused === 'bottom' ? focusedInputColor : convertedAmountColor }
|
||||
]}
|
||||
maxLength={9}
|
||||
keyboardType="decimal-pad"
|
||||
|
||||
@@ -23,7 +23,8 @@ interface ModalProps extends ViewProps {
|
||||
top?: number
|
||||
onBackdropPress?: any
|
||||
onBackButtonPress?: any
|
||||
backdropOpacity?: number
|
||||
onModalHide?: () => void
|
||||
backdropOpacity?: number
|
||||
/**
|
||||
* The heading text to display if not using `headingTx`.
|
||||
*/
|
||||
@@ -109,11 +110,12 @@ interface ModalProps extends ViewProps {
|
||||
*/
|
||||
export function BottomModal(props: ModalProps) {
|
||||
const {
|
||||
isVisible = true,
|
||||
isVisible = true,
|
||||
onBackdropPress,
|
||||
onBackButtonPress,
|
||||
onModalHide,
|
||||
//backdropOpacity = Platform.OS === 'ios' ? 0.25 : 0,
|
||||
backdropOpacity = 0.25,
|
||||
backdropOpacity = 0.25,
|
||||
content,
|
||||
contentTx,
|
||||
contentTxOptions,
|
||||
@@ -175,6 +177,7 @@ export function BottomModal(props: ModalProps) {
|
||||
avoidKeyboard={Platform.OS === 'ios'}
|
||||
onBackdropPress={onBackdropPress}
|
||||
onBackButtonPress={onBackButtonPress}
|
||||
onModalHide={onModalHide}
|
||||
backdropOpacity={backdropOpacity}
|
||||
useNativeDriverForBackdrop={true}
|
||||
hideModalContentWhileAnimating={true}
|
||||
|
||||
@@ -8,6 +8,7 @@ import JSONTree from 'react-native-json-tree'
|
||||
import Clipboard from '@react-native-clipboard/clipboard'
|
||||
import { useStores } from '../models'
|
||||
import useIsInternetReachable from '../utils/useIsInternetReachable'
|
||||
import { useSafeAreaInsets } from 'react-native-safe-area-context'
|
||||
|
||||
type ErrorModalProps = {
|
||||
error: AppError
|
||||
@@ -58,22 +59,23 @@ export const ErrorModal: FC<ErrorModalProps> = function ({ error }) {
|
||||
}
|
||||
|
||||
const bg = useThemeColor('error')
|
||||
const insets = useSafeAreaInsets()
|
||||
|
||||
return (
|
||||
<BottomModal
|
||||
isVisible={isErrorVisible}
|
||||
onBackdropPress={onClose}
|
||||
onBackButtonPress={onClose}
|
||||
onBackButtonPress={onClose}
|
||||
style={{ marginBottom: Platform.OS === 'android' ? -(insets.top + insets.bottom) : 0 }}
|
||||
ContentComponent={
|
||||
<>
|
||||
<View>
|
||||
<View style={{ flexDirection: 'row', alignItems: 'center', marginBottom: spacing.small }}>
|
||||
<Icon icon="faTriangleExclamation" size={spacing.large} color={bg} />
|
||||
<Text style={{ marginLeft: spacing.small }}>{error.name}</Text>
|
||||
</View>
|
||||
<ScrollView
|
||||
style={{
|
||||
//height: spacing.screenHeight * 0.1,
|
||||
maxHeight: spacing.screenHeight * 0.07,
|
||||
style={{
|
||||
maxHeight: spacing.screenHeight * 0.1,
|
||||
}}>
|
||||
<Text style={{ marginBottom: spacing.small }}>{error.message}</Text>
|
||||
</ScrollView>
|
||||
@@ -147,7 +149,7 @@ export const ErrorModal: FC<ErrorModalProps> = function ({ error }) {
|
||||
</>
|
||||
)}
|
||||
|
||||
</>
|
||||
</View>
|
||||
}
|
||||
/>
|
||||
)
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import React, { FC, useState, useEffect } from 'react'
|
||||
import { View } from 'react-native'
|
||||
import { Platform, View } from 'react-native'
|
||||
import { BottomModal, Icon, Text } from '../components'
|
||||
import { spacing, useThemeColor } from '../theme'
|
||||
import { useSafeAreaInsets } from 'react-native-safe-area-context'
|
||||
|
||||
|
||||
type InfoModalProps = {
|
||||
@@ -25,12 +26,14 @@ export const InfoModal: FC<InfoModalProps> = function ({ message }) {
|
||||
|
||||
const backgroundColor = useThemeColor('info')
|
||||
const iconColor = useThemeColor('textDim')
|
||||
const insets = useSafeAreaInsets()
|
||||
|
||||
return (
|
||||
<BottomModal
|
||||
isVisible={isInfoVisible}
|
||||
onBackdropPress={() => onClose()}
|
||||
onBackButtonPress={() => onClose()}
|
||||
style={{ marginBottom: Platform.OS === 'android' ? -(insets.top + insets.bottom) : 0 }}
|
||||
ContentComponent={
|
||||
<View style={{ padding: spacing.small, flexDirection: 'row', alignItems: 'center', marginRight: spacing.medium}}>
|
||||
<Icon icon="faInfoCircle" size={spacing.large} color={iconColor} />
|
||||
|
||||
@@ -1,23 +1,21 @@
|
||||
import {observer} from 'mobx-react-lite'
|
||||
import React, {useEffect, useRef, useState} from 'react'
|
||||
import {FlatList, TextInput, TextStyle, View, ViewStyle} from 'react-native'
|
||||
import {FlatList, Platform, TextInput, TextStyle, View, ViewStyle} from 'react-native'
|
||||
import {verticalScale} from '@gocodingnow/rn-size-matters'
|
||||
import {colors, spacing, useThemeColor} from '../../theme'
|
||||
import {BottomModal, Button, Card, ErrorModal, Icon, InfoModal, ListItem, Loading, Screen, Text} from '../../components'
|
||||
import {useStores} from '../../models'
|
||||
import { MinibitsClient, NostrClient, NostrProfile } from '../../services'
|
||||
import { NostrClient, NostrProfile } from '../../services'
|
||||
import AppError, { Err } from '../../utils/AppError'
|
||||
import {MINIBITS_NIP05_DOMAIN} from '@env'
|
||||
import { log } from '../../services/logService'
|
||||
import { ContactListItem } from './ContactListItem'
|
||||
import { Contact, ContactType } from '../../models/Contact'
|
||||
import { StackNavigationProp } from '@react-navigation/stack'
|
||||
import { ReceiveOption } from '../ReceiveScreen'
|
||||
import { SendOption } from '../SendScreen'
|
||||
import { infoMessage, warningMessage } from '../../utils/utils'
|
||||
import { IncomingDataType, IncomingParser } from '../../services/incomingParser'
|
||||
import { translate } from '../../i18n'
|
||||
import { RouteProp, useNavigation } from '@react-navigation/native'
|
||||
import { useNavigation } from '@react-navigation/native'
|
||||
import { toJS } from 'mobx'
|
||||
import { TransferOption } from '../TransferScreen'
|
||||
|
||||
@@ -32,11 +30,12 @@ export const PrivateContacts = observer(function (props: {
|
||||
const contactNameInputRef = useRef<TextInput>(null)
|
||||
|
||||
const [info, setInfo] = useState('')
|
||||
const [newContactName, setNewContactName] = useState<string>('')
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
const [isExternalDomain, setIsExternalDomain] = useState(false)
|
||||
const [isNewContactModalVisible, setIsNewContactModalVisible] = useState(false)
|
||||
const [newContactName, setNewContactName] = useState<string>('')
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
const [isExternalDomain, setIsExternalDomain] = useState(false)
|
||||
const [isNewContactModalVisible, setIsNewContactModalVisible] = useState(false)
|
||||
const [error, setError] = useState<AppError | undefined>()
|
||||
const [pendingError, setPendingError] = useState<AppError | undefined>()
|
||||
|
||||
useEffect(() => {
|
||||
const { paymentOption } = props
|
||||
@@ -127,7 +126,11 @@ export const PrivateContacts = observer(function (props: {
|
||||
} catch(e: any) {
|
||||
setNewContactName('')
|
||||
setIsExternalDomain(false)
|
||||
handleError(e)
|
||||
if (Platform.OS === 'ios') {
|
||||
setPendingError(e)
|
||||
} else {
|
||||
handleError(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -308,6 +311,12 @@ export const PrivateContacts = observer(function (props: {
|
||||
</View>
|
||||
<BottomModal
|
||||
isVisible={isNewContactModalVisible ? true : false}
|
||||
onModalHide={() => {
|
||||
if (pendingError) {
|
||||
handleError(pendingError)
|
||||
setPendingError(undefined)
|
||||
}
|
||||
}}
|
||||
ContentComponent={
|
||||
<View style={$newContainer}>
|
||||
<Text tx="contactsScreen_newTitle" preset="subheading" />
|
||||
|
||||
@@ -219,11 +219,8 @@ export const PublicContactsNew = observer(function (props: {
|
||||
setFollowingProfiles(following)
|
||||
setIsLoading(false)
|
||||
}
|
||||
|
||||
InteractionManager.runAfterInteractions(async () => {
|
||||
loadProfiles()
|
||||
})
|
||||
|
||||
|
||||
loadProfiles()
|
||||
|
||||
}, [followingPubkeys])
|
||||
|
||||
|
||||
@@ -49,6 +49,7 @@ export const MintsScreen = observer(function MintsScreen({ route }: Props) {
|
||||
const [selectedMint, setSelectedMint] = useState<Mint | undefined>()
|
||||
const [info, setInfo] = useState('')
|
||||
const [error, setError] = useState<AppError | undefined>()
|
||||
const [pendingError, setPendingError] = useState<AppError | undefined>()
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
const [isAddMintVisible, setIsAddMintVisible] = useState(false)
|
||||
const [isMintMenuVisible, setIsMintMenuVisible] = useState(false)
|
||||
@@ -119,7 +120,11 @@ export const MintsScreen = observer(function MintsScreen({ route }: Props) {
|
||||
setInfo(translate('mintsScreen_mintAdded'))
|
||||
} catch (e: any) {
|
||||
setMintUrl('')
|
||||
handleError(e)
|
||||
if (Platform.OS === 'ios') {
|
||||
setPendingError(e)
|
||||
} else {
|
||||
handleError(e)
|
||||
}
|
||||
} finally {
|
||||
setMintUrl('')
|
||||
setIsLoading(false)
|
||||
@@ -425,6 +430,12 @@ export const MintsScreen = observer(function MintsScreen({ route }: Props) {
|
||||
/>
|
||||
<BottomModal
|
||||
isVisible={isAddMintVisible ? true : false}
|
||||
onModalHide={() => {
|
||||
if (pendingError) {
|
||||
handleError(pendingError)
|
||||
setPendingError(undefined)
|
||||
}
|
||||
}}
|
||||
ContentComponent={
|
||||
<View style={$bottomModal}>
|
||||
<Text
|
||||
|
||||
@@ -27,40 +27,25 @@ export const getImageSource = function(img: string) {
|
||||
|
||||
|
||||
export const infoMessage = function(message: string, description?: string) {
|
||||
const backgroundColor = colors.palette.success300
|
||||
const backgroundColor = colors.palette.neutral500
|
||||
const textColor = 'white'
|
||||
|
||||
return showMessage({
|
||||
message,
|
||||
description,
|
||||
description,
|
||||
duration: 3000,
|
||||
backgroundColor,
|
||||
color: textColor,
|
||||
style: {
|
||||
minHeight: spacing.screenHeight * 0.15,
|
||||
borderTopLeftRadius: spacing.medium,
|
||||
borderTopRightRadius: spacing.medium
|
||||
minHeight: spacing.screenHeight * 0.05,
|
||||
borderRadius: spacing.medium,
|
||||
margin: spacing.large,
|
||||
marginBottom: spacing.large * 4,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
export const warningMessage = function(message: string, description?: string) {
|
||||
const backgroundColor = colors.palette.accent500
|
||||
|
||||
return showMessage({
|
||||
message,
|
||||
description,
|
||||
duration: 3000,
|
||||
backgroundColor,
|
||||
color: 'white',
|
||||
style: {
|
||||
minHeight: spacing.screenHeight * 0.15,
|
||||
borderTopLeftRadius: spacing.medium,
|
||||
borderTopRightRadius: spacing.medium
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export const generateId = function (lengthInBytes: number) {
|
||||
const random = QuickCrypto.randomBytes(lengthInBytes)
|
||||
const uint8Array = new Uint8Array(random)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: Minibits Wallet
|
||||
summary: Minibits is an ecash and Lightning wallet exploring how ₿-backed ecash can enable instant, cheap, and private value transfer.
|
||||
summary: Minibits is a Bitcoin Lightning and ecash wallet that deliver instant, low-cost, and private value transfers — even when the payer is offline.
|
||||
repository: https://github.com/minibits-cash/minibits_wallet
|
||||
homepage: https://minibits.cash/
|
||||
assets:
|
||||
|
||||
Reference in New Issue
Block a user