Skip to content

Commit

Permalink
feat #1385: App integration with NFC cards
Browse files Browse the repository at this point in the history
  • Loading branch information
Samuel Tremko committed Nov 30, 2024
1 parent 662c217 commit bdda349
Show file tree
Hide file tree
Showing 93 changed files with 1,487 additions and 367 deletions.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
33 changes: 30 additions & 3 deletions apps/mobile/app.config.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// import {SemverString} from '@vexl-next/domain/src/utility/SmeverString.brand'

const VERSION_CODE = 211
const VERSION = '1.17.0'
const VERSION_CODE = 349
const VERSION = '1.24.0'
const ENV_PRESET = process.env.ENV_PRESET
const COMMIT_HASH = process.env.EAS_BUILD_GIT_COMMIT_HASH ?? 'local'

Expand Down Expand Up @@ -54,6 +54,7 @@ export default {
'icon': extra.icon,
'userInterfaceStyle': 'light',
'jsEngine': 'hermes',
'scheme': 'app.vexl.it',
'platforms': ['ios', 'android'],
'splash': {
'image': './assets/splash.png',
Expand Down Expand Up @@ -87,7 +88,12 @@ export default {
// 'NSAppTransportSecurity': {'NSAllowsArbitraryLoads': true},
},
'googleServicesFile': extra.googleServicesInfoPlistFile,
'associatedDomains': ['applinks:link.vexl.it', 'applinks:nextlink.vexl.it'],
'associatedDomains': [
'applinks:vexl.it',
'applinks:app.vexl.it',
'applinks:link.vexl.it',
'applinks:nextlink.vexl.it',
],
'privacyManifests': {
'NSPrivacyAccessedAPITypes': [
{
Expand Down Expand Up @@ -117,6 +123,17 @@ export default {
'package': extra.packageName,
'googleServicesFile': './creds/google-services.json',
'intentFilters': [
// {
// 'action': 'NDEF_DISCOVERED',
// 'data': [
// {
// 'scheme': 'https',
// 'host': 'app.vexl.it',
// 'pathPattern': '.*',
// },
// ],
// category: ['DEFAULT'],
// },
{
'action': 'VIEW',
'autoVerify': true,
Expand All @@ -126,6 +143,11 @@ export default {
'host': 'vexl.it',
'pathPattern': '.*',
},
{
'scheme': 'https',
'host': 'app.vexl.it',
'pathPattern': '.*',
},
{
'scheme': 'https',
'host': 'link.vexl.it',
Expand All @@ -136,6 +158,11 @@ export default {
'host': 'nextlink.vexl.it',
'pathPattern': '.*',
},
{
'scheme': 'https',
'host': 'link.2.vexl.it',
'pathPattern': '.*',
},
],
category: ['BROWSABLE', 'DEFAULT'],
},
Expand Down
10 changes: 10 additions & 0 deletions apps/mobile/eas.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,16 @@
},
"channel": "staging"
},
"development-simulator": {
"developmentClient": true,
"distribution": "internal",
"env": {
"ENV_PRESET": "stage"
},
"ios": {
"simulator": true
}
},
"stagingApk": {
"android": {
"credentialsSource": "remote",
Expand Down
1 change: 1 addition & 0 deletions apps/mobile/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
"expo-haptics": "~13.0.1",
"expo-image-picker": "~15.0.7",
"expo-linear-gradient": "~13.0.2",
"expo-linking": "~6.3.1",
"expo-localization": "~15.0.3",
"expo-secure-store": "~13.0.2",
"expo-sharing": "~12.0.1",
Expand Down
2 changes: 1 addition & 1 deletion apps/mobile/src/brands/Session.brand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,4 @@ export const SessionE = Schema.Struct({
sessionCredentials: UserSessionCredentialsE,
privateKey: KeyHolder.PrivateKeyHolderE,
})
export type Session = Schema.Schema.Type<typeof SessionE>
export type Session = typeof SessionE.Type

Large diffs are not rendered by default.

48 changes: 41 additions & 7 deletions apps/mobile/src/components/AnonymousAvatar/index.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import {type GoldenAvatarType} from '@vexl-next/domain/src/general/offers'
import {type SvgString} from '@vexl-next/domain/src/utility/SvgString.brand'
import {type StyleProp, type ViewStyle} from 'react-native'
import {randomNumberFromSeed} from '../../utils/randomNumber'
import Image from '../Image'
import UserAvatar from '../UserAvatar'
import avatarsGoldenGlassesAndBackgroundSvg from './images/avatarsGoldenGlassesAndBackgroundSvg'
import avatarsSvg from './images/avatarsSvg'

interface Props {
Expand All @@ -21,33 +23,65 @@ function AnonymousAvatar({avatarIndex, style}: Props): JSX.Element {

export default AnonymousAvatar

export function getAvatarSvg(avatarIndex: number): SvgString {
export function getAvatarSvg({
avatarIndex,
goldenAvatarType,
}: {
avatarIndex: number
goldenAvatarType?: GoldenAvatarType
}): SvgString {
if (goldenAvatarType === 'BACKGROUND_AND_GLASSES')
return (
avatarsGoldenGlassesAndBackgroundSvg[avatarIndex] ??
avatarsGoldenGlassesAndBackgroundSvg[0]
)
return avatarsSvg[avatarIndex] ?? avatarsSvg[0]
}

export function getRandomAvatarSvgFromSeed(seed: string): SvgString {
const randomNumber = randomNumberFromSeed(0, avatarsSvg.length - 1, seed)
return getAvatarSvg(randomNumber)
export function getRandomAvatarSvgFromSeed({
seed,
goldenAvatarType,
}: {
seed: string
goldenAvatarType?: GoldenAvatarType
}): SvgString {
const randomNumber = randomNumberFromSeed(
0,
goldenAvatarType === 'BACKGROUND_AND_GLASSES'
? avatarsGoldenGlassesAndBackgroundSvg.length - 1
: avatarsSvg.length - 1,
seed
)
return getAvatarSvg({avatarIndex: randomNumber, goldenAvatarType})
}

export function AnonymousAvatarFromSeed({
seed,
width,
height,
grayScale,
goldenAvatarType,
}: {
seed: string
height: number
width: number
grayScale: boolean
goldenAvatarType?: GoldenAvatarType
}): JSX.Element {
const avatar =
avatarsSvg[randomNumberFromSeed(0, avatarsSvg.length - 1, seed)] ??
avatarsSvg[0]
goldenAvatarType === 'BACKGROUND_AND_GLASSES'
? avatarsGoldenGlassesAndBackgroundSvg[
randomNumberFromSeed(
0,
avatarsGoldenGlassesAndBackgroundSvg.length - 1,
seed
)
]
: avatarsSvg[randomNumberFromSeed(0, avatarsSvg.length - 1, seed)]

return (
<UserAvatar
userImage={{type: 'svgXml', svgXml: avatar}}
userImage={{type: 'svgXml', svgXml: avatar ?? avatarsSvg[0]}}
width={width}
height={height}
grayScale={grayScale}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ import {currencies} from '../../../utils/localization/currency'
import getDefaultSpokenLanguage from '../../../utils/localization/getDefaultSpokenLanguage'
import notEmpty from '../../../utils/notEmpty'
import checkNotificationPermissionsAndAskIfPossibleActionAtom from '../../../utils/notifications/checkAndAskForPermissionsActionAtom'
import {preferencesAtom} from '../../../utils/preferences'
import reportError from '../../../utils/reportError'
import showErrorAlert from '../../../utils/showErrorAlert'
import {toCommonErrorMessage} from '../../../utils/useCommonErrorMessages'
Expand Down Expand Up @@ -591,6 +592,7 @@ export const offerFormMolecule = molecule(() => {

const intendedConnectionLevel = get(intendedConnectionLevelAtom)
const belowProgressLeft = get(modifyOfferLoaderTitleAtom)
const {goldenAvatarType} = get(preferencesAtom)
const payloadPublic = formatOfferPublicPart(get(offerFormAtom))

return pipe(
Expand All @@ -616,6 +618,7 @@ export const offerFormMolecule = molecule(() => {
...payloadPublic,
authorClientVersion: version,
offerPublicKey: key.publicKeyPemBase64,
goldenAvatarType,
},
intendedConnectionLevel: intendedConnectionLevel ?? 'FIRST',
onProgress: (progress) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {type UriString} from '@vexl-next/domain/src/utility/UriString.brand'
import {atom, useAtom, useAtomValue, useSetAtom} from 'jotai'
import {useEffect} from 'react'
import {Stack, XStack, getTokens} from 'tamagui'
import {realUserImageAtom} from '../../state/session'
import {realUserImageAtom} from '../../state/session/userDataAtoms'
import {useTranslation} from '../../utils/localization/I18nProvider'
import useSafeGoBack from '../../utils/useSafeGoBack'
import Button from '../Button'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ import {normalizedContactsAtom} from '../../../state/contacts/atom/contactsStore
import {createBtcPriceForCurrencyAtom} from '../../../state/currentBtcPriceAtoms'
import {createFeedbackForChatAtom} from '../../../state/feedback/atoms'
import {offerForChatOriginAtom} from '../../../state/marketplace/atoms/offersState'
import {invalidUsernameUIFeedbackAtom} from '../../../state/session'
import {invalidUsernameUIFeedbackAtom} from '../../../state/session/userDataAtoms'
import * as amount from '../../../state/tradeChecklist/utils/amount'
import {getAmountData} from '../../../state/tradeChecklist/utils/amount'
import * as dateAndTime from '../../../state/tradeChecklist/utils/dateAndTime'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import useResetNavigationToMessagingScreen from '../../../utils/useResetNavigati
import AnimatedModal from '../../AnimatedModal'
import {useReportOfferHandleUI} from '../../OfferDetailScreen/api'
import flagSvg from '../../OfferDetailScreen/images/flagSvg'
import ParticipatedInMeetup from '../../ParticipatedInMeetup'
import IdentityIconSvg from '../../images/identityIconSvg'
import {chatMolecule} from '../atoms'
import vexlbotNotificationsSvg from '../images/vexlbotNotificationsSvg'
Expand Down Expand Up @@ -90,6 +91,12 @@ function ChatInfoModal(): JSX.Element | null {
<Text>(this will NOT be visible in production)</Text>
</>
)}
{chat.origin.type === 'theirOffer' &&
!!offerForChat?.offerInfo.publicPart.goldenAvatarType && (
<Stack mb="$7">
<ParticipatedInMeetup />
</Stack>
)}
<ButtonStack
buttons={[
...(canSendMessages && identityRevealStatus === 'notStarted'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {generateOtherSideSeed} from '../../../state/chat/atoms/selectOtherSideDa
import {type ChatMessageWithState} from '../../../state/chat/domain'
import {useTranslation} from '../../../utils/localization/I18nProvider'
import {randomNumberFromSeed} from '../../../utils/randomNumber'
import avatarsGoldenGlassesAndBackgroundSvg from '../../AnonymousAvatar/images/avatarsGoldenGlassesAndBackgroundSvg'
import avatarsSvg from '../../AnonymousAvatar/images/avatarsSvg'
import SvgImage from '../../Image'
import {revealIdentityFromQuickActionBannerAtom} from '../../TradeChecklistFlow/atoms/revealIdentityAtoms'
Expand All @@ -31,10 +32,12 @@ function IdentityRevealMessageItem({
revealIdentityWithUiFeedbackAtom,
publicKeyPemBase64Atom,
chatIdAtom,
offerForChatAtom,
} = useMolecule(chatMolecule)
const {image, userName, partialPhoneNumber} = useAtomValue(otherSideDataAtom)
const chat = useAtomValue(chatAtom)
const chatId = useAtomValue(chatIdAtom)
const offer = useAtomValue(offerForChatAtom)
const inboxKey = useAtomValue(publicKeyPemBase64Atom)
const identityRevealStatus = useAtomValue(identityRevealStatusAtom)
const revealIdentity = useSetAtom(revealIdentityWithUiFeedbackAtom)
Expand All @@ -44,17 +47,22 @@ function IdentityRevealMessageItem({
const revealIdentityFromQuickActionBanner = useSetAtom(
revealIdentityFromQuickActionBannerAtom
)
const anonymousAvatars =
offer?.offerInfo.publicPart.goldenAvatarType === 'BACKGROUND_AND_GLASSES' &&
!offer.ownershipInfo?.adminId
? avatarsGoldenGlassesAndBackgroundSvg
: avatarsSvg

const anonymousImage = useMemo(
() =>
avatarsSvg[
anonymousAvatars[
randomNumberFromSeed(
0,
avatarsSvg.length - 1,
anonymousAvatars.length - 1,
generateOtherSideSeed(chat)
)
],
[chat]
[anonymousAvatars, chat]
)

if (
Expand Down
2 changes: 1 addition & 1 deletion apps/mobile/src/components/EditNameScreen/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {Stack, getTokens} from 'tamagui'
import {
invalidUsernameUIFeedbackAtom,
realUserNameAtom,
} from '../../state/session'
} from '../../state/session/userDataAtoms'
import {useTranslation} from '../../utils/localization/I18nProvider'
import useSafeGoBack from '../../utils/useSafeGoBack'
import Button from '../Button'
Expand Down
13 changes: 12 additions & 1 deletion apps/mobile/src/components/EmptyListWrapper.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import {useAtomValue} from 'jotai'
import {RefreshControl, ScrollView} from 'react-native'
import {Stack, YStack, getTokens} from 'tamagui'
import {goldenAvatarTypeAtom} from '../utils/preferences'
import Button from './Button'
import Image from './Image'
import usePixelsFromBottomWhereTabsEnd from './InsideRouter/utils'
import anonymousAvatarHappyGoldenGlassesNoBackgroundSvg from './images/anonymousAvatarHappyGoldenGlassesNoBackgroundSvg'
import anonymousAvatarHappyNoBackgroundSvg from './images/anonymousAvatarHappyNoBackgroundSvg'

interface ContentProps {
Expand All @@ -16,10 +19,18 @@ function EmptyListContent({
buttonText,
onButtonPress,
}: ContentProps): JSX.Element {
const goldenAvatarType = useAtomValue(goldenAvatarTypeAtom)

return (
<YStack f={1} ai="center" jc="center" py="$4" gap="$4">
<Stack ai="center" jc="center" p="$2" bc="$grey" br="$6">
<Image source={anonymousAvatarHappyNoBackgroundSvg} />
<Image
source={
goldenAvatarType
? anonymousAvatarHappyGoldenGlassesNoBackgroundSvg
: anonymousAvatarHappyNoBackgroundSvg
}
/>
</Stack>
{children}
{!!buttonText && !!onButtonPress && (
Expand Down
9 changes: 8 additions & 1 deletion apps/mobile/src/components/Info.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,14 @@ function Info({
setIsVisible(false)
}}
>
<SvgImage stroke={tokens.color.pink.val} source={closeSvg} />
<SvgImage
stroke={
variant === 'pink'
? tokens.color.pink.val
: tokens.color.main.val
}
source={closeSvg}
/>
</TouchableOpacity>
)}
</XStack>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import {stringToSvgStringRuntimeError} from '../../../../Image'

const avatarBackgroundSvg =
stringToSvgStringRuntimeError(`<svg width="150" height="150" viewBox="0 0 150 150" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="150" height="150" rx="20" fill="white"/>
</svg>
`)

export default avatarBackgroundSvg
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import {stringToSvgStringRuntimeError} from '../../../../Image'

const avatarGlassesSvg =
stringToSvgStringRuntimeError(`<svg width="150" height="150" viewBox="0 0 150 150" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M42.1206 58.1077H108.132V62.781H42.1206V58.1077Z" fill="black"/>
<path d="M69.3892 70.7715C69.3892 70.7715 64.7657 66.148 59.0624 60.4446C53.359 54.7413 48.7356 50.1178 48.7356 50.1178C54.4389 44.4145 63.6859 44.4145 69.3892 50.1178C75.0925 55.8212 75.0925 65.0681 69.3892 70.7715Z" fill="#333333"/>
<path d="M69.3895 70.7716C63.6861 76.4749 54.4392 76.4749 48.7358 70.7716C43.0325 65.0682 43.0325 55.8213 48.7358 50.1179C48.7358 50.1179 53.3593 54.7414 59.0627 60.4447C64.766 66.1481 69.3895 70.7716 69.3895 70.7716Z" fill="black"/>
<path d="M101.519 70.7715C101.519 70.7715 96.895 66.148 91.1917 60.4446C85.4883 54.7413 80.8648 50.1178 80.8648 50.1178C86.5682 44.4145 95.8151 44.4145 101.519 50.1178C107.222 55.8212 107.222 65.0681 101.519 70.7715Z" fill="#333333"/>
<path d="M101.519 70.7716C95.8153 76.4749 86.5683 76.4749 80.865 70.7716C75.1616 65.0682 75.1616 55.8213 80.865 50.1179C80.865 50.1179 85.4885 54.7414 91.1918 60.4447C96.8951 66.1481 101.519 70.7716 101.519 70.7716Z" fill="black"/>
</svg>
`)

export default avatarGlassesSvg
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import {stringToSvgStringRuntimeError} from '../../../../Image'

const avatarSvg1 =
stringToSvgStringRuntimeError(`<svg width="150" height="150" viewBox="0 0 150 150" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M75.12 15H99C105.627 15 111 20.3726 111 27V75H75.12V15Z" fill="#ACD9B7"/>
</svg>
`)

export default avatarSvg1
Loading

0 comments on commit bdda349

Please sign in to comment.