Skip to content

Commit

Permalink
feat(ios): proximity flow
Browse files Browse the repository at this point in the history
Signed-off-by: Berend Sliedrecht <berend@animo.id>
  • Loading branch information
berendsliedrecht committed Jan 22, 2025
1 parent caef0ce commit 61b851d
Show file tree
Hide file tree
Showing 32 changed files with 4,236 additions and 4,875 deletions.
6 changes: 5 additions & 1 deletion apps/easypid/app.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ const config = {
'@animo-id/expo-mdoc-data-transfer',
{
ios: {
buildStatic: [],
buildStatic: ['RNReanimated', 'RNScreens', 'aries-askar', 'anoncreds', 'indy_vdr'],
},
},
],
Expand All @@ -87,6 +87,10 @@ const config = {
useLegacyPackaging: true,
extraMavenRepos: ['https://s01.oss.sonatype.org/content/repositories/snapshots/'],
},
ios: {
deploymentTarget: '15.1',
useFrameworks: 'dynamic',
},
},
],
[
Expand Down
22 changes: 15 additions & 7 deletions apps/easypid/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
"@expo-google-fonts/raleway": "^0.2.3",
"@hyperledger/anoncreds-react-native": "catalog:",
"@hyperledger/aries-askar-react-native": "catalog:",
"@hyperledger/indy-vdr-react-native": "catalog:",
"@package/agent": "workspace:*",
"@package/app": "workspace:*",
"@package/scanner": "workspace:*",
Expand Down Expand Up @@ -54,26 +53,35 @@
"expo-web-browser": "~13.0.3",
"fast-text-encoding": "^1.0.6",
"react": "catalog:",
"react-native": "catalog:",
"react-native": "^0.75.4",
"react-native-argon2": "^2.0.1",
"react-native-executorch": "^0.1.2",
"react-native-fs": "^2.20.0",
"react-native-gesture-handler": "~2.16.2",
"react-native-gesture-handler": "~2.18.1",
"react-native-get-random-values": "~1.11.0",
"react-native-keychain": "^8.2.0",
"react-native-mmkv": "^2.12.2",
"react-native-qrcode-svg": "^6.3.12",
"react-native-reanimated": "~3.10.1",
"react-native-reanimated": "~3.15.5",
"react-native-reanimated-carousel": "^3.5.1",
"react-native-safe-area-context": "4.10.5",
"react-native-screens": "~3.31.1",
"react-native-screens": "~3.34.1",
"react-native-svg": "15.9.0"
},
"devDependencies": {
"@babel/core": "^7.24.4",
"@tamagui/babel-plugin": "1.109.5",
"@tamagui/babel-plugin": "1.122.6",
"babel-plugin-syntax-hermes-parser": "^0.25.1",
"expo-build-properties": "^0.12.5",
"typescript": "catalog:"
},
"expo": {
"install": {
"exclude": [
"react-native@~0.74.0",
"react-native-reanimated@~3.10.0",
"react-native-gesture-handler@~2.16.1",
"react-native-screens@~3.31.1"
]
}
}
}
4 changes: 2 additions & 2 deletions apps/easypid/src/app/_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { DefaultTheme, ThemeProvider } from '@react-navigation/native'
import { Slot } from 'expo-router'
import * as SplashScreen from 'expo-splash-screen'

import { useCheckIncompleteDownload } from '@easypid/llm'
// import { useCheckIncompleteDownload } from '@easypid/llm'
import tamaguiConfig from '../../tamagui.config'

void SplashScreen.preventAutoHideAsync()
Expand All @@ -18,7 +18,7 @@ export const unstable_settings = {

export default function RootLayout() {
useTransparentNavigationBar()
useCheckIncompleteDownload()
// useCheckIncompleteDownload()

return (
<Provider config={tamaguiConfig}>
Expand Down
4 changes: 2 additions & 2 deletions apps/easypid/src/features/menu/FunkeSettingsScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { FlexPage, HeaderContainer, HeroIcons, ScrollView, Switch, YStack } from
import React from 'react'

import { TextBackButton } from 'packages/app/src'
import { LocalAiContainer } from './components/LocalAiContainer'
// import { LocalAiContainer } from './components/LocalAiContainer'

import { useScrollViewPosition } from '@package/app/src/hooks'
import { useDevelopmentMode } from '../../hooks/useDevelopmentMode'
Expand All @@ -28,7 +28,7 @@ export function FunkeSettingsScreen() {
value={isDevelopmentModeEnabled ?? false}
onChange={setIsDevelopmentModeEnabled}
/>
<LocalAiContainer />
{/* <LocalAiContainer /> */}
</YStack>
<YStack btw="$0.5" borderColor="$grey-200" pt="$4" mx="$-4" px="$4" bg="$background">
<TextBackButton />
Expand Down
198 changes: 99 additions & 99 deletions apps/easypid/src/features/menu/components/LocalAiContainer.tsx
Original file line number Diff line number Diff line change
@@ -1,99 +1,99 @@
import { HeroIcons } from '@package/ui/src/content/Icon'

import { Switch } from '@package/ui/src/base/Switch'

import { useIsDeviceCapable, useLLM } from '@easypid/llm'
import { ConfirmationSheet } from '@package/app/src/components/ConfirmationSheet'
import { useHasInternetConnection, useIsConnectedToWifi } from 'packages/app/src/hooks'
import { useToastController } from 'packages/ui/src'
import React, { useState } from 'react'

export function LocalAiContainer() {
const toast = useToastController()
const isConnectedToWifi = useIsConnectedToWifi()
const hasInternetConnection = useHasInternetConnection()
const isDeviceCapable = useIsDeviceCapable()

const [isAiModelConfirmationOpen, setIsAiModelConfirmationOpen] = useState(false)
const { loadModel, isModelReady, downloadProgress, removeModel, isModelActivated, isModelDownloading } = useLLM()

const onActivateModel = () => {
if (!isDeviceCapable) {
toast.show('Device not supported', {
message: 'This device is not powerful enough to run local AI models',
customData: {
preset: 'warning',
},
})
setIsAiModelConfirmationOpen(false)
return
}
if (!isConnectedToWifi && !hasInternetConnection) {
toast.show('WiFi connection required', {
message: 'Please connect to WiFi to activate and download the model',
customData: {
preset: 'warning',
},
})
setIsAiModelConfirmationOpen(false)
return
}

setIsAiModelConfirmationOpen(false)
loadModel()
}

const handleAiModelChange = (value: boolean) => {
if (isModelDownloading) {
toast.show('Model download in progress', {
message: 'Force close the app to cancel the download',
customData: {
preset: 'warning',
},
})
return
}

if (value) {
setIsAiModelConfirmationOpen(true)
} else {
removeModel()
}
}

return (
<>
<Switch
id="local-ai-model"
label="Use local AI model"
icon={<HeroIcons.CpuChipFilled />}
value={isModelActivated}
description={
isModelActivated
? isModelReady
? 'Model active and ready to use'
: downloadProgress
? `Downloading model ${(downloadProgress * 100).toFixed(2)}%`
: 'Getting ready...'
: ''
}
onChange={handleAiModelChange}
beta
/>
<ConfirmationSheet
type="floating"
variant="regular"
isOpen={isAiModelConfirmationOpen}
setIsOpen={setIsAiModelConfirmationOpen}
title="Enable local AI model"
confirmText="Enable"
cancelText="Cancel"
description={[
'This will download a local AI model to your device which will take up to around 1.3GB of space.',
'This is an experimental feature. Only supported on high-end devices.',
]}
onConfirm={onActivateModel}
/>
</>
)
}
// import { HeroIcons } from '@package/ui/src/content/Icon'
//
// import { Switch } from '@package/ui/src/base/Switch'
//
// import { useIsDeviceCapable, useLLM } from '@easypid/llm'
// import { ConfirmationSheet } from '@package/app/src/components/ConfirmationSheet'
// import { useHasInternetConnection, useIsConnectedToWifi } from 'packages/app/src/hooks'
// import { useToastController } from 'packages/ui/src'
// import React, { useState } from 'react'
//
// export function LocalAiContainer() {
// const toast = useToastController()
// const isConnectedToWifi = useIsConnectedToWifi()
// const hasInternetConnection = useHasInternetConnection()
// const isDeviceCapable = useIsDeviceCapable()
//
// const [isAiModelConfirmationOpen, setIsAiModelConfirmationOpen] = useState(false)
// const { loadModel, isModelReady, downloadProgress, removeModel, isModelActivated, isModelDownloading } = useLLM()
//
// const onActivateModel = () => {
// if (!isDeviceCapable) {
// toast.show('Device not supported', {
// message: 'This device is not powerful enough to run local AI models',
// customData: {
// preset: 'warning',
// },
// })
// setIsAiModelConfirmationOpen(false)
// return
// }
// if (!isConnectedToWifi && !hasInternetConnection) {
// toast.show('WiFi connection required', {
// message: 'Please connect to WiFi to activate and download the model',
// customData: {
// preset: 'warning',
// },
// })
// setIsAiModelConfirmationOpen(false)
// return
// }
//
// setIsAiModelConfirmationOpen(false)
// loadModel()
// }
//
// const handleAiModelChange = (value: boolean) => {
// if (isModelDownloading) {
// toast.show('Model download in progress', {
// message: 'Force close the app to cancel the download',
// customData: {
// preset: 'warning',
// },
// })
// return
// }
//
// if (value) {
// setIsAiModelConfirmationOpen(true)
// } else {
// removeModel()
// }
// }
//
// return (
// <>
// <Switch
// id="local-ai-model"
// label="Use local AI model"
// icon={<HeroIcons.CpuChipFilled />}
// value={isModelActivated}
// description={
// isModelActivated
// ? isModelReady
// ? 'Model active and ready to use'
// : downloadProgress
// ? `Downloading model ${(downloadProgress * 100).toFixed(2)}%`
// : 'Getting ready...'
// : ''
// }
// onChange={handleAiModelChange}
// beta
// />
// <ConfirmationSheet
// type="floating"
// variant="regular"
// isOpen={isAiModelConfirmationOpen}
// setIsOpen={setIsAiModelConfirmationOpen}
// title="Enable local AI model"
// confirmText="Enable"
// cancelText="Cancel"
// description={[
// 'This will download a local AI model to your device which will take up to around 1.3GB of space.',
// 'This is an experimental feature. Only supported on high-end devices.',
// ]}
// onConfirm={onActivateModel}
// />
// </>
// )
// }
21 changes: 11 additions & 10 deletions apps/easypid/src/features/proximity/mdocProximity.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { mdocDataTransfer } from '@animo-id/expo-mdoc-data-transfer'
import {
COSEKey,
DataItem,
Expand All @@ -15,9 +16,6 @@ import type { EasyPIDAppAgent, FormattedSubmission, MdocRecord } from '@package/
import { handleBatchCredential } from '@package/agent/src/batch'
import { type Permission, PermissionsAndroid, Platform } from 'react-native'

const requireMdocDataTransfer = () =>
require('@animo-id/expo-mdoc-data-transfer') as typeof import('@animo-id/expo-mdoc-data-transfer')

type ShareDeviceResponseOptions = {
sessionTranscript: Uint8Array
deviceRequest: Uint8Array
Expand Down Expand Up @@ -53,8 +51,7 @@ export const checkMdocPermissions = async () => {
}

export const getMdocQrCode = async () => {
const mdt = requireMdocDataTransfer().mdocDataTransfer.instance()
mdt.enableNfc()
const mdt = mdocDataTransfer.instance()
const qrData = await mdt.startQrEngagement()
return qrData
}
Expand All @@ -67,10 +64,12 @@ export const getMdocQrCode = async () => {
*
*/
export const waitForDeviceRequest = async () => {
const mdt = requireMdocDataTransfer().mdocDataTransfer.instance()
const mdt = mdocDataTransfer.instance()
const { deviceRequest, sessionTranscript } = await mdt.waitForDeviceRequest()

const encodedSessionTranscript = cborEncode(DataItem.fromData(cborDecode(sessionTranscript)))
// current bug on android required re-encapsulation
const encodedSessionTranscript =
Platform.OS === 'android' ? cborEncode(DataItem.fromData(cborDecode(sessionTranscript))) : sessionTranscript

return { deviceRequest, sessionTranscript: encodedSessionTranscript }
}
Expand Down Expand Up @@ -114,7 +113,7 @@ export const shareDeviceResponse = async (options: ShareDeviceResponseOptions) =
crypto: MdocContext['crypto']
}

const mdt = requireMdocDataTransfer().mdocDataTransfer.instance()
const mdt = mdocDataTransfer.instance()

if (mdoc.documents.length > 1) {
throw new Error('Only one mdoc supported at the moment due to only being able to sign with one device key')
Expand All @@ -134,10 +133,12 @@ export const shareDeviceResponse = async (options: ShareDeviceResponseOptions) =
.authenticateWithSignature(publicDeviceJwk, 'ES256')
.sign(mdocContext)

console.log(Platform.OS, ':', Buffer.from(deviceResponse.encode()).toString('hex'))

await mdt.sendDeviceResponse(deviceResponse.encode())
}

export const shutdownDataTransfer = () => {
const mdt = requireMdocDataTransfer().mdocDataTransfer.instance()
mdt.shutdown()
// const mdt = mdocDataTransfer.instance()
// mdt.shutdown()
}
Loading

0 comments on commit 61b851d

Please sign in to comment.