Skip to content

Commit

Permalink
fix: offline permissions
Browse files Browse the repository at this point in the history
Signed-off-by: Jan <[email protected]>
  • Loading branch information
janrtvld committed Dec 19, 2024
1 parent 9310512 commit a65f84c
Show file tree
Hide file tree
Showing 8 changed files with 121 additions and 40 deletions.
2 changes: 1 addition & 1 deletion apps/easypid/src/features/activity/FunkeActivityScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export function FunkeActivityScreen({ entityId }: { entityId?: string }) {
return (
<FlexPage gap="$0" paddingHorizontal="$0">
<YStack w="100%" top={0} borderBottomWidth="$0.5" borderColor={isScrolledByOffset ? '$grey-200' : '$background'}>
<YStack gap="$2" p="$4">
<YStack gap="$4" p="$4">
<Stack h="$1" />
<Heading variant="h1">Activity</Heading>
</YStack>
Expand Down
4 changes: 2 additions & 2 deletions apps/easypid/src/features/wallet/FunkeCredentialsScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export function FunkeCredentialsScreen() {
return (
<FlexPage gap="$0" paddingHorizontal="$0">
<YStack w="100%" top={0} borderBottomWidth="$0.5" borderColor={isScrolledByOffset ? '$grey-200' : '$background'}>
<YStack gap="$2" p="$4">
<YStack gap="$4" p="$4">
<Stack h="$1" />
<Heading variant="h1">Cards</Heading>
</YStack>
Expand Down Expand Up @@ -161,7 +161,7 @@ function FunkeCredentialRowCard({ name, backgroundColor, textColor, logo, onPres
Issued on {formatDate(new Date(), { includeTime: false })}
</Paragraph>
</YStack>
<IconContainer icon={<HeroIcons.ArrowRight color={textColor} size={20} />} />
<IconContainer bg="transparent" icon={<HeroIcons.ArrowRight color={textColor} size={20} />} />
</AnimatedStack>
)
}
82 changes: 72 additions & 10 deletions apps/easypid/src/features/wallet/FunkeOfflineQrScreen.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { mmkv } from '@easypid/storage/mmkv'
import {
AnimatedStack,
Button,
Expand All @@ -14,27 +15,94 @@ import {
import { useRouter } from 'expo-router'
import { useHaptics } from 'packages/app/src'
import { useEffect, useState } from 'react'
import { Platform, useWindowDimensions } from 'react-native'
import { Alert, Linking, useWindowDimensions } from 'react-native'
import { useMMKVBoolean } from 'react-native-mmkv'
import QRCode from 'react-native-qrcode-svg'
import easypidLogo from '../../../assets/icon-rounded.png'
import { checkMdocPermissions, shutdownDataTransfer, waitForDeviceRequest } from '../proximity'
import {
checkMdocPermissions,
getMdocQrCode,
requestMdocPermissions,
shutdownDataTransfer,
waitForDeviceRequest,
} from '../proximity'

export function FunkeOfflineQrScreen() {
const { withHaptics } = useHaptics()
const { replace, back } = useRouter()
const { width } = useWindowDimensions()
const toast = useToastController()
const [isProcessing, setIsProcessing] = useState(false)
const [isLoading, setIsLoading] = useState(false)

const [qrCodeData, setQrCodeData] = useState<string>()
const [arePermissionsGranted, setArePermissionsGranted] = useState(false)
const [arePermissionsRequested, setArePermissionsRequested] = useMMKVBoolean('arePermissionsRequested', mmkv)

useEffect(() => {
void checkMdocPermissions().then((result) => {
setArePermissionsGranted(!!result)
if (!result) {
void requestPermissions()
}
})
}, [])

useEffect(() => {
if (arePermissionsGranted) {
void getMdocQrCode().then(setQrCodeData)
} else {
setQrCodeData(undefined)
}
}, [arePermissionsGranted])

const handlePermissions = async () => {
const permissions = await requestMdocPermissions()

if (!permissions) {
toast.show('Failed to request permissions.', { customData: { preset: 'danger' } })
return { granted: false, shouldShowSettings: false }
}

// Check if any permission is in 'never_ask_again' state
const hasNeverAskAgain = Object.values(permissions).some((status) => status === 'never_ask_again')

if (hasNeverAskAgain) {
return { granted: false, shouldShowSettings: true }
}

const permissionStatus = await checkMdocPermissions()
return { granted: !!permissionStatus, shouldShowSettings: false }
}

const requestPermissions = async () => {
// First request without checking the never_ask_again state
if (!arePermissionsRequested) {
const { granted } = await handlePermissions()
setArePermissionsRequested(true)
setArePermissionsGranted(granted)
return
}

// Subsequent requests need to check for the never_ask_again state
const { granted, shouldShowSettings } = await handlePermissions()

if (shouldShowSettings) {
back()
Alert.alert(
'Please enable required permissions in your phone settings',
'Sharing with QR-Code needs access to Bluetooth and Location.',
[
{
text: 'Open Settings',
onPress: () => Linking.openSettings(),
},
]
)
return
}

setArePermissionsGranted(granted)
}

useEffect(() => {
if (qrCodeData) {
void waitForDeviceRequest().then((data) => {
Expand Down Expand Up @@ -69,12 +137,6 @@ export function FunkeOfflineQrScreen() {
shutdownDataTransfer()
}

if (Platform.OS === 'ios') {
toast.show('This feature is not supported on your OS yet.', { customData: { preset: 'warning' } })
back()
return
}

return (
<Page bg="$black" ai="center">
<AnimatedStack pt="$8" maxWidth="90%" gap="$2">
Expand Down
28 changes: 19 additions & 9 deletions apps/easypid/src/features/wallet/FunkeWalletScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@ import {
XStack,
YStack,
useSpringify,
useToastController,
} from '@package/ui'
import { useRouter } from 'expo-router'

import { useFirstNameFromPidCredential } from '@easypid/hooks'
import { useHaptics } from '@package/app/src/hooks'
import { Platform } from 'react-native'
import { FadeIn } from 'react-native-reanimated'
import { Blob } from '../../../assets/Blob'
import { ActionCard } from './components/ActionCard'
Expand All @@ -26,27 +28,35 @@ import { LatestActivityCard } from './components/LatestActivityCard'
export function FunkeWalletScreen() {
const { push } = useRouter()
const { withHaptics } = useHaptics()
const toast = useToastController()

const { userName, isLoading } = useFirstNameFromPidCredential()

const pushToMenu = withHaptics(() => push('/menu'))
const pushToScanner = withHaptics(() => push('/scan'))
const pushToPidSetup = withHaptics(() => push('/pidSetup'))
const pushToAbout = withHaptics(() => push('/menu/about'))
const pushToOffline = withHaptics(() => push('/offline'))
const pushToOffline = () => {
if (Platform.OS === 'ios') {
toast.show('This feature is not supported on your OS yet.', { customData: { preset: 'warning' } })
return
}

withHaptics(() => push('/offline'))()
}

return (
<YStack pos="relative" fg={1}>
<YStack pos="absolute" h="50%" w="100%">
<Blob />
<Blob key=" 123444535r5ffff4" />
</YStack>

<FlexPage safeArea="y" fg={1} flex-1={false} bg="transparent">
<XStack py="$3">
<IconContainer bg aria-label="Menu" icon={<HeroIcons.Menu />} onPress={pushToMenu} />
<IconContainer bg="white" aria-label="Menu" icon={<HeroIcons.Menu />} onPress={pushToMenu} />
</XStack>

<AnimatedStack fg={1} entering={useSpringify(FadeIn, 200)}>
<AnimatedStack fg={1} entering={useSpringify(FadeIn, 200)} opacity={0}>
<ScrollView contentContainerStyle={{ fg: 1 }}>
<YStack fg={1} f={1} gap="$4">
<YStack ai="center" jc="center" gap="$2">
Expand All @@ -58,19 +68,19 @@ export function FunkeWalletScreen() {
>
{userName ? `Hello, ${userName}!` : 'Hello!'}
</Heading>
<Paragraph>Select what you want to do</Paragraph>
<Paragraph>Receive or share from your wallet</Paragraph>
</YStack>
<XStack gap="$4" jc="center" py="$3">
<XStack gap="$4" jc="center" py="$2" w="95%" mx="auto">
<ActionCard
variant="primary"
icon={<CustomIcons.Qr color="white" />}
title="QR-code"
title="Scan QR-code"
onPress={pushToScanner}
/>
<ActionCard
variant="secondary"
icon={<CustomIcons.People size={26} />}
title="In-person"
title="Present In-person"
onPress={pushToOffline}
/>
</XStack>
Expand All @@ -81,7 +91,7 @@ export function FunkeWalletScreen() {
</Button.Text>
) : (
<Button.Text scaleOnPress bg="transparent" onPress={pushToPidSetup}>
Setup your ID
Setup your ID <HeroIcons.ArrowRight ml="$-2.5" color="$primary-500" size={16} />
</Button.Text>
)}
</XStack>
Expand Down
24 changes: 15 additions & 9 deletions apps/easypid/src/features/wallet/components/ActionCard.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AnimatedStack, Heading, Stack, useScaleAnimation } from '@package/ui'
import { AnimatedStack, Heading, Stack, XStack, YStack, useScaleAnimation } from '@package/ui'
import type { ReactNode } from 'react'

interface ActionCardProps {
Expand All @@ -21,18 +21,24 @@ export function ActionCard({ icon, title, onPress, variant = 'primary' }: Action
onPressIn={qrHandlePressIn}
onPressOut={qrHandlePressOut}
onPress={onPress}
ai="center"
jc="center"
bg={variant === 'primary' ? '$grey-900' : '$white'}
py="$4"
px="$6"
gap="$4"
p="$3"
fg={1}
gap="$3"
br="$6"
>
<Stack>{icon}</Stack>
<Heading color={variant === 'primary' ? 'white' : '$grey-900'} variant="h2">
{title}
</Heading>
<XStack jc="space-between" ai="center">
<Stack />
{icon}
</XStack>
<YStack>
{title.split(' ').map((word) => (
<Heading key={word} color={variant === 'primary' ? 'white' : '$grey-900'} variant="h2">
{word}
</Heading>
))}
</YStack>
</AnimatedStack>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,11 @@ export function LatestActivityCard() {
const pushToActivity = withHaptics(() => push('/activity'))

const content = useMemo(() => {
if (!latestActivity) return null
if (!latestActivity)
return {
title: 'Recent activity',
description: 'No activity yet',
}
if (latestActivity.type === 'shared') {
const isPlural = latestActivity.request.credentials.length > 1
return {
Expand Down
4 changes: 2 additions & 2 deletions packages/ui/src/components/ProgressHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,9 @@ export function ProgressHeader({
mx={variant === 'small' ? '$-4' : '$0'}
>
{variant === 'small' ? (
<Stack pos="absolute" h={1} w="100%" bg="$grey-200" />
<Stack pos="absolute" h={1} w="100%" bg="$grey-50" />
) : (
<Stack pos="absolute" h={12} w="100%" br={24} bg="$grey-200" />
<Stack pos="absolute" h={12} w="100%" br={24} bg="$grey-50" />
)}
<AnimatedStack
accessibilityRole="progressbar"
Expand Down
11 changes: 5 additions & 6 deletions packages/ui/src/content/IconContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@ import { useScaleAnimation } from '../hooks'
interface IconContainerProps extends Omit<StackProps, 'bg'> {
icon: React.ReactElement
scaleOnPress?: boolean
bg?: boolean
bg?: 'white' | 'grey' | 'transparent'
'aria-label'?: string
}

export function IconContainer({
icon,
scaleOnPress = true,
bg = false,
bg = 'grey',
'aria-label': ariaLabel,
...props
}: IconContainerProps) {
Expand All @@ -23,16 +23,15 @@ export function IconContainer({
<AnimatedStack
accessible={true}
accessibilityRole="button"
p="$3"
m="$-3"
style={pressStyle}
onPressIn={handlePressIn}
onPressOut={handlePressOut}
aria-label={ariaLabel}
pos="relative"
bg={bg === 'white' ? '$white' : bg === 'grey' ? '$grey-50' : 'transparent'}
br="$12"
p="$2"
{...props}
>
{bg && <Circle pos="absolute" bg="$white" m="$2" size={36} />}
{cloneElement(icon, {
strokeWidth: icon.props.strokeWidth ?? 2,
size: icon.props.size ?? 24,
Expand Down

0 comments on commit a65f84c

Please sign in to comment.