Add `PlatformInfo` module (#4877)
parent
fb278384c6
commit
18b423396b
|
@ -95,3 +95,13 @@ jest.mock('expo-application', () => ({
|
||||||
nativeApplicationVersion: '1.0.0',
|
nativeApplicationVersion: '1.0.0',
|
||||||
nativeBuildVersion: '1',
|
nativeBuildVersion: '1',
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
jest.mock('expo-modules-core', () => ({
|
||||||
|
requireNativeModule: jest.fn().mockImplementation(moduleName => {
|
||||||
|
if (moduleName === 'ExpoPlatformInfo') {
|
||||||
|
return {
|
||||||
|
getIsReducedMotionEnabled: () => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
}))
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
package expo.modules.blueskyswissarmy.platforminfo
|
||||||
|
|
||||||
|
import android.provider.Settings
|
||||||
|
import expo.modules.kotlin.modules.Module
|
||||||
|
import expo.modules.kotlin.modules.ModuleDefinition
|
||||||
|
|
||||||
|
class ExpoPlatformInfoModule : Module() {
|
||||||
|
override fun definition() =
|
||||||
|
ModuleDefinition {
|
||||||
|
Name("ExpoPlatformInfo")
|
||||||
|
|
||||||
|
// See https://github.com/software-mansion/react-native-reanimated/blob/7df5fd57d608fe25724608835461cd925ff5151d/packages/react-native-reanimated/android/src/main/java/com/swmansion/reanimated/nativeProxy/NativeProxyCommon.java#L242
|
||||||
|
Function("getIsReducedMotionEnabled") {
|
||||||
|
val resolver = appContext.reactContext?.contentResolver ?: return@Function false
|
||||||
|
val scale = Settings.Global.getString(resolver, Settings.Global.TRANSITION_ANIMATION_SCALE) ?: return@Function false
|
||||||
|
|
||||||
|
try {
|
||||||
|
return@Function scale.toFloat() == 0f
|
||||||
|
} catch (_: Error) {
|
||||||
|
return@Function false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,12 +1,13 @@
|
||||||
{
|
{
|
||||||
"platforms": ["ios", "tvos", "android", "web"],
|
"platforms": ["ios", "tvos", "android", "web"],
|
||||||
"ios": {
|
"ios": {
|
||||||
"modules": ["ExpoBlueskySharedPrefsModule", "ExpoBlueskyReferrerModule"]
|
"modules": ["ExpoBlueskySharedPrefsModule", "ExpoBlueskyReferrerModule", "ExpoPlatformInfoModule"]
|
||||||
},
|
},
|
||||||
"android": {
|
"android": {
|
||||||
"modules": [
|
"modules": [
|
||||||
"expo.modules.blueskyswissarmy.sharedprefs.ExpoBlueskySharedPrefsModule",
|
"expo.modules.blueskyswissarmy.sharedprefs.ExpoBlueskySharedPrefsModule",
|
||||||
"expo.modules.blueskyswissarmy.referrer.ExpoBlueskyReferrerModule"
|
"expo.modules.blueskyswissarmy.referrer.ExpoBlueskyReferrerModule",
|
||||||
|
"expo.modules.blueskyswissarmy.platforminfo.ExpoPlatformInfoModule"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
|
import * as PlatformInfo from './src/PlatformInfo'
|
||||||
import * as Referrer from './src/Referrer'
|
import * as Referrer from './src/Referrer'
|
||||||
import * as SharedPrefs from './src/SharedPrefs'
|
import * as SharedPrefs from './src/SharedPrefs'
|
||||||
|
|
||||||
export {Referrer, SharedPrefs}
|
export {PlatformInfo, Referrer, SharedPrefs}
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
import ExpoModulesCore
|
||||||
|
|
||||||
|
public class ExpoPlatformInfoModule: Module {
|
||||||
|
public func definition() -> ModuleDefinition {
|
||||||
|
Name("ExpoPlatformInfo")
|
||||||
|
|
||||||
|
Function("getIsReducedMotionEnabled") {
|
||||||
|
return UIAccessibility.isReduceMotionEnabled
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
import {requireNativeModule} from 'expo-modules-core'
|
||||||
|
|
||||||
|
const NativeModule = requireNativeModule('ExpoPlatformInfo')
|
||||||
|
|
||||||
|
export function getIsReducedMotionEnabled(): boolean {
|
||||||
|
return NativeModule.getIsReducedMotionEnabled()
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
import {NotImplementedError} from '../NotImplemented'
|
||||||
|
|
||||||
|
export function getIsReducedMotionEnabled(): boolean {
|
||||||
|
throw new NotImplementedError()
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
export function getIsReducedMotionEnabled(): boolean {
|
||||||
|
if (typeof window === 'undefined') {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return window.matchMedia('(prefers-reduced-motion: reduce)').matches
|
||||||
|
}
|
|
@ -207,31 +207,3 @@ index 88b3fdf..2488ebc 100644
|
||||||
|
|
||||||
const { layout, entering, exiting, sharedTransitionTag } = this.props;
|
const { layout, entering, exiting, sharedTransitionTag } = this.props;
|
||||||
if (
|
if (
|
||||||
diff --git a/node_modules/react-native-reanimated/lib/module/reanimated2/index.js b/node_modules/react-native-reanimated/lib/module/reanimated2/index.js
|
|
||||||
index ac9be5d..86d4605 100644
|
|
||||||
--- a/node_modules/react-native-reanimated/lib/module/reanimated2/index.js
|
|
||||||
+++ b/node_modules/react-native-reanimated/lib/module/reanimated2/index.js
|
|
||||||
@@ -47,4 +47,5 @@ export { LayoutAnimationConfig } from './component/LayoutAnimationConfig';
|
|
||||||
export { PerformanceMonitor } from './component/PerformanceMonitor';
|
|
||||||
export { startMapper, stopMapper } from './mappers';
|
|
||||||
export { startScreenTransition, finishScreenTransition, ScreenTransition } from './screenTransition';
|
|
||||||
+export { isReducedMotion } from './PlatformChecker';
|
|
||||||
//# sourceMappingURL=index.js.map
|
|
||||||
diff --git a/node_modules/react-native-reanimated/lib/typescript/reanimated2/index.d.ts b/node_modules/react-native-reanimated/lib/typescript/reanimated2/index.d.ts
|
|
||||||
index f01dc57..161ef22 100644
|
|
||||||
--- a/node_modules/react-native-reanimated/lib/typescript/reanimated2/index.d.ts
|
|
||||||
+++ b/node_modules/react-native-reanimated/lib/typescript/reanimated2/index.d.ts
|
|
||||||
@@ -36,3 +36,4 @@ export type { FlatListPropsWithLayout } from './component/FlatList';
|
|
||||||
export { startMapper, stopMapper } from './mappers';
|
|
||||||
export { startScreenTransition, finishScreenTransition, ScreenTransition, } from './screenTransition';
|
|
||||||
export type { AnimatedScreenTransition, GoBackGesture, ScreenTransitionConfig, } from './screenTransition';
|
|
||||||
+export { isReducedMotion } from './PlatformChecker';
|
|
||||||
diff --git a/node_modules/react-native-reanimated/src/reanimated2/index.ts b/node_modules/react-native-reanimated/src/reanimated2/index.ts
|
|
||||||
index 5885fa1..a3c693f 100644
|
|
||||||
--- a/node_modules/react-native-reanimated/src/reanimated2/index.ts
|
|
||||||
+++ b/node_modules/react-native-reanimated/src/reanimated2/index.ts
|
|
||||||
@@ -284,3 +284,4 @@ export type {
|
|
||||||
GoBackGesture,
|
|
||||||
ScreenTransitionConfig,
|
|
||||||
} from './screenTransition';
|
|
||||||
+export { isReducedMotion } from './PlatformChecker';
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import {Platform} from 'react-native'
|
import {Platform} from 'react-native'
|
||||||
import {isReducedMotion} from 'react-native-reanimated'
|
|
||||||
import {getLocales} from 'expo-localization'
|
import {getLocales} from 'expo-localization'
|
||||||
|
|
||||||
import {fixLegacyLanguageCode} from '#/locale/helpers'
|
import {fixLegacyLanguageCode} from '#/locale/helpers'
|
||||||
|
@ -21,5 +20,3 @@ export const deviceLocales = dedupArray(
|
||||||
.map?.(locale => fixLegacyLanguageCode(locale.languageCode))
|
.map?.(locale => fixLegacyLanguageCode(locale.languageCode))
|
||||||
.filter(code => typeof code === 'string'),
|
.filter(code => typeof code === 'string'),
|
||||||
) as string[]
|
) as string[]
|
||||||
|
|
||||||
export const prefersReducedMotion = isReducedMotion()
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import {AccessibilityInfo} from 'react-native'
|
import {AccessibilityInfo} from 'react-native'
|
||||||
import {isReducedMotion} from 'react-native-reanimated'
|
|
||||||
|
|
||||||
import {isWeb} from '#/platform/detection'
|
import {isWeb} from '#/platform/detection'
|
||||||
|
import {PlatformInfo} from '../../modules/expo-bluesky-swiss-army'
|
||||||
|
|
||||||
const Context = React.createContext({
|
const Context = React.createContext({
|
||||||
reduceMotionEnabled: false,
|
reduceMotionEnabled: false,
|
||||||
|
@ -15,7 +15,7 @@ export function useA11y() {
|
||||||
|
|
||||||
export function Provider({children}: React.PropsWithChildren<{}>) {
|
export function Provider({children}: React.PropsWithChildren<{}>) {
|
||||||
const [reduceMotionEnabled, setReduceMotionEnabled] = React.useState(() =>
|
const [reduceMotionEnabled, setReduceMotionEnabled] = React.useState(() =>
|
||||||
isReducedMotion(),
|
PlatformInfo.getIsReducedMotionEnabled(),
|
||||||
)
|
)
|
||||||
const [screenReaderEnabled, setScreenReaderEnabled] = React.useState(false)
|
const [screenReaderEnabled, setScreenReaderEnabled] = React.useState(false)
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import {z} from 'zod'
|
import {z} from 'zod'
|
||||||
|
|
||||||
import {deviceLocales, prefersReducedMotion} from '#/platform/detection'
|
import {deviceLocales} from '#/platform/detection'
|
||||||
|
import {PlatformInfo} from '../../../modules/expo-bluesky-swiss-army'
|
||||||
|
|
||||||
const externalEmbedOptions = ['show', 'hide'] as const
|
const externalEmbedOptions = ['show', 'hide'] as const
|
||||||
|
|
||||||
|
@ -128,7 +129,7 @@ export const defaults: Schema = {
|
||||||
lastSelectedHomeFeed: undefined,
|
lastSelectedHomeFeed: undefined,
|
||||||
pdsAddressHistory: [],
|
pdsAddressHistory: [],
|
||||||
disableHaptics: false,
|
disableHaptics: false,
|
||||||
disableAutoplay: prefersReducedMotion,
|
disableAutoplay: PlatformInfo.getIsReducedMotionEnabled(),
|
||||||
kawaii: false,
|
kawaii: false,
|
||||||
hasCheckedForStarterPack: false,
|
hasCheckedForStarterPack: false,
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import {Button, ButtonText} from '#/components/Button'
|
||||||
import * as Dialog from '#/components/Dialog'
|
import * as Dialog from '#/components/Dialog'
|
||||||
import * as Prompt from '#/components/Prompt'
|
import * as Prompt from '#/components/Prompt'
|
||||||
import {H3, P, Text} from '#/components/Typography'
|
import {H3, P, Text} from '#/components/Typography'
|
||||||
|
import {PlatformInfo} from '../../../../modules/expo-bluesky-swiss-army'
|
||||||
|
|
||||||
export function Dialogs() {
|
export function Dialogs() {
|
||||||
const scrollable = Dialog.useDialogControl()
|
const scrollable = Dialog.useDialogControl()
|
||||||
|
@ -17,6 +18,8 @@ export function Dialogs() {
|
||||||
const testDialog = Dialog.useDialogControl()
|
const testDialog = Dialog.useDialogControl()
|
||||||
const {closeAllDialogs} = useDialogStateControlContext()
|
const {closeAllDialogs} = useDialogStateControlContext()
|
||||||
const unmountTestDialog = Dialog.useDialogControl()
|
const unmountTestDialog = Dialog.useDialogControl()
|
||||||
|
const [reducedMotionEnabled, setReducedMotionEnabled] =
|
||||||
|
React.useState<boolean>()
|
||||||
const [shouldRenderUnmountTest, setShouldRenderUnmountTest] =
|
const [shouldRenderUnmountTest, setShouldRenderUnmountTest] =
|
||||||
React.useState(false)
|
React.useState(false)
|
||||||
const unmountTestInterval = React.useRef<number>()
|
const unmountTestInterval = React.useRef<number>()
|
||||||
|
@ -147,6 +150,22 @@ export function Dialogs() {
|
||||||
<ButtonText>Open Shared Prefs Tester</ButtonText>
|
<ButtonText>Open Shared Prefs Tester</ButtonText>
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
variant="solid"
|
||||||
|
color="primary"
|
||||||
|
size="small"
|
||||||
|
onPress={() => {
|
||||||
|
const isReducedMotionEnabled =
|
||||||
|
PlatformInfo.getIsReducedMotionEnabled()
|
||||||
|
setReducedMotionEnabled(isReducedMotionEnabled)
|
||||||
|
}}
|
||||||
|
label="two">
|
||||||
|
<ButtonText>
|
||||||
|
Is reduced motion enabled?: (
|
||||||
|
{reducedMotionEnabled?.toString() || 'undefined'})
|
||||||
|
</ButtonText>
|
||||||
|
</Button>
|
||||||
|
|
||||||
<Prompt.Outer control={prompt}>
|
<Prompt.Outer control={prompt}>
|
||||||
<Prompt.TitleText>This is a prompt</Prompt.TitleText>
|
<Prompt.TitleText>This is a prompt</Prompt.TitleText>
|
||||||
<Prompt.DescriptionText>
|
<Prompt.DescriptionText>
|
||||||
|
|
Loading…
Reference in New Issue