Added reduced motion

This commit is contained in:
Zhiyuan Zheng 2021-03-27 00:02:32 +01:00
parent d490cae955
commit b0b7a7567b
No known key found for this signature in database
GPG Key ID: 078A93AB607D85E0
10 changed files with 127 additions and 47 deletions

View File

@ -7,6 +7,7 @@ import log from '@root/startup/log'
import netInfo from '@root/startup/netInfo'
import sentry from '@root/startup/sentry'
import { persistor, store } from '@root/store'
import AccessibilityManager from '@utils/accessibility/AccessibilityManager'
import { getSettingsLanguage } from '@utils/slices/settingsSlice'
import ThemeManager from '@utils/styles/ThemeManager'
import * as Notifications from 'expo-notifications'
@ -90,9 +91,11 @@ const App: React.FC = () => {
i18n.changeLanguage(getSettingsLanguage(store.getState()))
return (
<ActionSheetProvider>
<AccessibilityManager>
<ThemeManager>
<Screens localCorrupt={localCorrupt} />
</ThemeManager>
</AccessibilityManager>
</ActionSheetProvider>
)
} else {

View File

@ -1,9 +1,11 @@
import { useAccessibility } from '@utils/accessibility/AccessibilityManager'
import { getSettingsFontsize } from '@utils/slices/settingsSlice'
import { StyleConstants } from '@utils/styles/constants'
import { adaptiveScale } from '@utils/styles/scaling'
import { useTheme } from '@utils/styles/ThemeManager'
import React, { useMemo } from 'react'
import { Image, StyleSheet, Text } from 'react-native'
import { StyleSheet, Text } from 'react-native'
import FastImage from 'react-native-fast-image'
import { useSelector } from 'react-redux'
const regexEmoji = new RegExp(/(:[A-Za-z0-9_]+:)/)
@ -24,6 +26,8 @@ const ParseEmojis = React.memo(
adaptiveSize = false,
fontBold = false
}: Props) => {
const { reduceMotionEnabled } = useAccessibility()
const adaptiveFontsize = useSelector(getSettingsFontsize)
const adaptedFontsize = adaptiveScale(
StyleConstants.Font.Size[size],
@ -69,9 +73,13 @@ const ParseEmojis = React.memo(
<Text key={i}>
{/* When emoji starts a paragraph, lineHeight will break */}
{i === 0 ? <Text> </Text> : null}
<Image
<FastImage
key={adaptiveFontsize}
source={{ uri: emojis[emojiIndex].url }}
source={{
uri: reduceMotionEnabled
? emojis[emojiIndex].static_url
: emojis[emojiIndex].url
}}
style={styles.image}
/>
</Text>

View File

@ -33,9 +33,10 @@ const TimelineAvatar = React.memo(
height: StyleConstants.Avatar.M
}}
style={{
borderRadius: 4,
borderRadius: StyleConstants.Avatar.M,
overflow: 'hidden',
marginRight: StyleConstants.Spacing.S
marginRight: StyleConstants.Spacing.S,
backgroundColor: 'red'
}}
/>
)

View File

@ -6,6 +6,7 @@ import { ParseHTML } from '@components/Parse'
import RelativeTime from '@components/RelativeTime'
import { BlurView } from '@react-native-community/blur'
import { StackScreenProps } from '@react-navigation/stack'
import { useAccessibility } from '@utils/accessibility/AccessibilityManager'
import {
useAnnouncementMutation,
useAnnouncementQuery
@ -14,15 +15,9 @@ import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
import React, { useCallback, useEffect, useState } from 'react'
import { Trans, useTranslation } from 'react-i18next'
import {
Dimensions,
Image,
Pressable,
StyleSheet,
Text,
View
} from 'react-native'
import { Dimensions, Pressable, StyleSheet, Text, View } from 'react-native'
import { Circle } from 'react-native-animated-spinkit'
import FastImage from 'react-native-fast-image'
import { FlatList, ScrollView } from 'react-native-gesture-handler'
import { SafeAreaView } from 'react-native-safe-area-context'
@ -37,6 +32,7 @@ const ScreenAnnouncements: React.FC<ScreenAnnouncementsProp> = ({
},
navigation
}) => {
const { reduceMotionEnabled } = useAccessibility()
const { mode, theme } = useTheme()
const [index, setIndex] = useState(0)
const { t } = useTranslation('sharedAnnouncements')
@ -102,7 +98,9 @@ const ScreenAnnouncements: React.FC<ScreenAnnouncementsProp> = ({
style={[
styles.reaction,
{
borderColor: reaction.me ? theme.disabled : theme.primaryDefault,
borderColor: reaction.me
? theme.disabled
: theme.primaryDefault,
backgroundColor: reaction.me
? theme.disabled
: theme.backgroundDefault
@ -121,8 +119,12 @@ const ScreenAnnouncements: React.FC<ScreenAnnouncementsProp> = ({
}}
>
{reaction.url ? (
<Image
source={{ uri: reaction.url }}
<FastImage
source={{
uri: reduceMotionEnabled
? reaction.static_url
: reaction.url
}}
style={[styles.reactionImage]}
/>
) : (
@ -130,7 +132,10 @@ const ScreenAnnouncements: React.FC<ScreenAnnouncementsProp> = ({
)}
{reaction.count ? (
<Text
style={[styles.reactionCount, { color: theme.primaryDefault }]}
style={[
styles.reactionCount,
{ color: theme.primaryDefault }
]}
>
{reaction.count}
</Text>
@ -246,7 +251,8 @@ const ScreenAnnouncements: React.FC<ScreenAnnouncementsProp> = ({
styles.indicator,
{
borderColor: theme.primaryDefault,
backgroundColor: i === index ? theme.primaryDefault : undefined,
backgroundColor:
i === index ? theme.primaryDefault : undefined,
marginLeft:
i === query.data.length ? 0 : StyleConstants.Spacing.S
}

View File

@ -4,14 +4,8 @@ import { useSearchQuery } from '@utils/queryHooks/search'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
import { forEach, groupBy, sortBy } from 'lodash'
import React, {
useCallback,
useContext,
useEffect,
useMemo,
useRef
} from 'react'
import { FlatList, Image, StyleSheet, View } from 'react-native'
import React, { useCallback, useContext, useEffect, useMemo } from 'react'
import { FlatList, StyleSheet, View } from 'react-native'
import { Circle } from 'react-native-animated-spinkit'
import ComposeActions from './Root/Actions'
import ComposePosting from './Posting'
@ -20,24 +14,32 @@ import ComposeRootHeader from './Root/Header'
import ComposeRootSuggestion from './Root/Suggestion'
import ComposeContext from './utils/createContext'
import ComposeDrafts from './Root/Drafts'
import FastImage from 'react-native-fast-image'
import { useAccessibility } from '@utils/accessibility/AccessibilityManager'
const prefetchEmojis = (
sortedEmojis: { title: string; data: Mastodon.Emoji[] }[]
sortedEmojis: { title: string; data: Mastodon.Emoji[] }[],
reduceMotionEnabled: boolean
) => {
const prefetches: { uri: string }[] = []
let requestedIndex = 0
sortedEmojis.forEach(sorted => {
sorted.data.forEach(emoji => {
if (requestedIndex > 40) {
return
}
Image.prefetch(emoji.url)
prefetches.push({
uri: reduceMotionEnabled ? emoji.static_url : emoji.url
})
requestedIndex++
})
})
FastImage.preload(prefetches)
}
const ComposeRoot = React.memo(
() => {
const { reduceMotionEnabled } = useAccessibility()
const { theme } = useTheme()
const { composeState, composeDispatch } = useContext(ComposeContext)
@ -74,9 +76,9 @@ const ComposeRoot = React.memo(
type: 'emoji',
payload: { ...composeState.emoji, emojis: sortedEmojis }
})
prefetchEmojis(sortedEmojis)
prefetchEmojis(sortedEmojis, reduceMotionEnabled)
}
}, [emojisData])
}, [emojisData, reduceMotionEnabled])
const listEmpty = useMemo(() => {
if (isFetching) {

View File

@ -3,18 +3,15 @@ import haptics from '@components/haptics'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
import React, { useCallback, useContext, useMemo } from 'react'
import {
Image,
Pressable,
SectionList,
StyleSheet,
Text,
View
} from 'react-native'
import { Pressable, SectionList, StyleSheet, Text, View } from 'react-native'
import ComposeContext from '../../utils/createContext'
import updateText from '../../updateText'
import FastImage from 'react-native-fast-image'
import { useAccessibility } from '@utils/accessibility/AccessibilityManager'
const SingleEmoji = ({ emoji }: { emoji: Mastodon.Emoji }) => {
const { reduceMotionEnabled } = useAccessibility()
const { composeState, composeDispatch } = useContext(ComposeContext)
const onPress = useCallback(() => {
analytics('compose_emoji_add')
@ -32,8 +29,8 @@ const SingleEmoji = ({ emoji }: { emoji: Mastodon.Emoji }) => {
}, [composeState])
const children = useMemo(
() => (
<Image
source={{ uri: emoji.url, cache: 'force-cache' }}
<FastImage
source={{ uri: reduceMotionEnabled ? emoji.static_url : emoji.url }}
style={styles.emoji}
/>
),
@ -81,6 +78,7 @@ const ComposeEmojis: React.FC = () => {
keyExtractor={item => item.shortcode}
renderSectionHeader={listHeader}
renderItem={listItem}
windowSize={3}
/>
</View>
)

View File

@ -1,3 +1,4 @@
import { useAccessibility } from '@utils/accessibility/AccessibilityManager'
import { useTheme } from '@utils/styles/ThemeManager'
import React, { useContext } from 'react'
import { Dimensions, Image } from 'react-native'
@ -9,14 +10,17 @@ export interface Props {
limitHeight?: boolean
}
const AccountHeader: React.FC<Props> = ({ account, limitHeight = false }) => {
const AccountHeader: React.FC<Props> = ({ account }) => {
const { accountState } = useContext(AccountContext)
const { reduceMotionEnabled } = useAccessibility()
const { theme } = useTheme()
const topInset = useSafeAreaInsets().top
return (
<Image
source={{ uri: account?.header }}
source={{
uri: reduceMotionEnabled ? account?.header_static : account?.header
}}
style={{
height:
Dimensions.get('screen').width * accountState.headerRatio + topInset,

View File

@ -2,6 +2,7 @@ import analytics from '@components/analytics'
import GracefullyImage from '@components/GracefullyImage'
import { useNavigation } from '@react-navigation/native'
import { StackNavigationProp } from '@react-navigation/stack'
import { useAccessibility } from '@utils/accessibility/AccessibilityManager'
import { StyleConstants } from '@utils/styles/constants'
import React from 'react'
import { Pressable, StyleSheet } from 'react-native'
@ -15,6 +16,7 @@ const AccountInformationAvatar: React.FC<Props> = ({ account, myInfo }) => {
const navigation = useNavigation<
StackNavigationProp<Nav.TabLocalStackParamList>
>()
const { reduceMotionEnabled } = useAccessibility()
return (
<Pressable
@ -28,7 +30,11 @@ const AccountInformationAvatar: React.FC<Props> = ({ account, myInfo }) => {
<GracefullyImage
key={account?.avatar}
style={styles.image}
uri={{ original: account?.avatar }}
uri={{
original: reduceMotionEnabled
? account?.avatar_static
: account?.avatar
}}
/>
</Pressable>
)

View File

@ -0,0 +1,52 @@
import React, { createContext, useContext, useEffect, useState } from 'react'
import { AccessibilityInfo } from 'react-native'
type ContextType = {
reduceMotionEnabled: boolean
}
const AccessibilityContext = createContext<ContextType>({
reduceMotionEnabled: false
})
export const useAccessibility = () => useContext(AccessibilityContext)
const AccessibilityManager: React.FC = ({ children }) => {
const [reduceMotionEnabled, setReduceMotionEnabled] = useState(false)
const handleReduceMotionChanged = (reduceMotionEnabled: boolean) =>
setReduceMotionEnabled(reduceMotionEnabled)
const loadReduceMotion = async () => {
const reduceMotion = await AccessibilityInfo.isReduceMotionEnabled()
setReduceMotionEnabled(reduceMotion)
}
useEffect(() => {
loadReduceMotion()
AccessibilityInfo.addEventListener(
'reduceMotionChanged',
handleReduceMotionChanged
)
return () => {
AccessibilityInfo.removeEventListener(
'reduceMotionChanged',
handleReduceMotionChanged
)
}
}, [])
return (
<AccessibilityContext.Provider
value={{
reduceMotionEnabled
}}
>
{children}
</AccessibilityContext.Provider>
)
}
export default AccessibilityManager

View File

@ -11,7 +11,7 @@ type ContextType = {
setTheme: (theme: 'light' | 'dark') => void
}
export const ManageThemeContext = createContext<ContextType>({
const ManageThemeContext = createContext<ContextType>({
mode: 'light',
theme: getTheme('light'),
setTheme: () => {}