about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--jest/jestSetup.js10
-rw-r--r--modules/expo-bluesky-swiss-army/android/src/main/java/expo/modules/blueskyswissarmy/platforminfo/ExpoPlatformInfoModule.kt24
-rw-r--r--modules/expo-bluesky-swiss-army/expo-module.config.json5
-rw-r--r--modules/expo-bluesky-swiss-army/index.ts3
-rw-r--r--modules/expo-bluesky-swiss-army/ios/PlatformInfo/ExpoPlatformInfoModule.swift11
-rw-r--r--modules/expo-bluesky-swiss-army/src/PlatformInfo/index.native.ts7
-rw-r--r--modules/expo-bluesky-swiss-army/src/PlatformInfo/index.ts5
-rw-r--r--modules/expo-bluesky-swiss-army/src/PlatformInfo/index.web.ts6
-rw-r--r--patches/react-native-reanimated+3.11.0.patch28
-rw-r--r--src/platform/detection.ts3
-rw-r--r--src/state/a11y.tsx4
-rw-r--r--src/state/persisted/schema.ts5
-rw-r--r--src/view/screens/Storybook/Dialogs.tsx19
13 files changed, 92 insertions, 38 deletions
diff --git a/jest/jestSetup.js b/jest/jestSetup.js
index a6b7c24f6..ac175900e 100644
--- a/jest/jestSetup.js
+++ b/jest/jestSetup.js
@@ -95,3 +95,13 @@ jest.mock('expo-application', () => ({
   nativeApplicationVersion: '1.0.0',
   nativeBuildVersion: '1',
 }))
+
+jest.mock('expo-modules-core', () => ({
+  requireNativeModule: jest.fn().mockImplementation(moduleName => {
+    if (moduleName === 'ExpoPlatformInfo') {
+      return {
+        getIsReducedMotionEnabled: () => false,
+      }
+    }
+  }),
+}))
diff --git a/modules/expo-bluesky-swiss-army/android/src/main/java/expo/modules/blueskyswissarmy/platforminfo/ExpoPlatformInfoModule.kt b/modules/expo-bluesky-swiss-army/android/src/main/java/expo/modules/blueskyswissarmy/platforminfo/ExpoPlatformInfoModule.kt
new file mode 100644
index 000000000..189796f81
--- /dev/null
+++ b/modules/expo-bluesky-swiss-army/android/src/main/java/expo/modules/blueskyswissarmy/platforminfo/ExpoPlatformInfoModule.kt
@@ -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
+        }
+      }
+    }
+}
diff --git a/modules/expo-bluesky-swiss-army/expo-module.config.json b/modules/expo-bluesky-swiss-army/expo-module.config.json
index 1111f8a0b..adb535e7f 100644
--- a/modules/expo-bluesky-swiss-army/expo-module.config.json
+++ b/modules/expo-bluesky-swiss-army/expo-module.config.json
@@ -1,12 +1,13 @@
 {
   "platforms": ["ios", "tvos", "android", "web"],
   "ios": {
-    "modules": ["ExpoBlueskySharedPrefsModule", "ExpoBlueskyReferrerModule"]
+    "modules": ["ExpoBlueskySharedPrefsModule", "ExpoBlueskyReferrerModule", "ExpoPlatformInfoModule"]
   },
   "android": {
     "modules": [
       "expo.modules.blueskyswissarmy.sharedprefs.ExpoBlueskySharedPrefsModule",
-      "expo.modules.blueskyswissarmy.referrer.ExpoBlueskyReferrerModule"
+      "expo.modules.blueskyswissarmy.referrer.ExpoBlueskyReferrerModule",
+      "expo.modules.blueskyswissarmy.platforminfo.ExpoPlatformInfoModule"
     ]
   }
 }
diff --git a/modules/expo-bluesky-swiss-army/index.ts b/modules/expo-bluesky-swiss-army/index.ts
index 89cea00a2..f62596cb7 100644
--- a/modules/expo-bluesky-swiss-army/index.ts
+++ b/modules/expo-bluesky-swiss-army/index.ts
@@ -1,4 +1,5 @@
+import * as PlatformInfo from './src/PlatformInfo'
 import * as Referrer from './src/Referrer'
 import * as SharedPrefs from './src/SharedPrefs'
 
-export {Referrer, SharedPrefs}
+export {PlatformInfo, Referrer, SharedPrefs}
diff --git a/modules/expo-bluesky-swiss-army/ios/PlatformInfo/ExpoPlatformInfoModule.swift b/modules/expo-bluesky-swiss-army/ios/PlatformInfo/ExpoPlatformInfoModule.swift
new file mode 100644
index 000000000..4a1e6d7e7
--- /dev/null
+++ b/modules/expo-bluesky-swiss-army/ios/PlatformInfo/ExpoPlatformInfoModule.swift
@@ -0,0 +1,11 @@
+import ExpoModulesCore
+
+public class ExpoPlatformInfoModule: Module {
+  public func definition() -> ModuleDefinition {
+    Name("ExpoPlatformInfo")
+
+    Function("getIsReducedMotionEnabled") {
+      return UIAccessibility.isReduceMotionEnabled
+    }
+  }
+}
diff --git a/modules/expo-bluesky-swiss-army/src/PlatformInfo/index.native.ts b/modules/expo-bluesky-swiss-army/src/PlatformInfo/index.native.ts
new file mode 100644
index 000000000..e05f173d6
--- /dev/null
+++ b/modules/expo-bluesky-swiss-army/src/PlatformInfo/index.native.ts
@@ -0,0 +1,7 @@
+import {requireNativeModule} from 'expo-modules-core'
+
+const NativeModule = requireNativeModule('ExpoPlatformInfo')
+
+export function getIsReducedMotionEnabled(): boolean {
+  return NativeModule.getIsReducedMotionEnabled()
+}
diff --git a/modules/expo-bluesky-swiss-army/src/PlatformInfo/index.ts b/modules/expo-bluesky-swiss-army/src/PlatformInfo/index.ts
new file mode 100644
index 000000000..9b9b7fc0c
--- /dev/null
+++ b/modules/expo-bluesky-swiss-army/src/PlatformInfo/index.ts
@@ -0,0 +1,5 @@
+import {NotImplementedError} from '../NotImplemented'
+
+export function getIsReducedMotionEnabled(): boolean {
+  throw new NotImplementedError()
+}
diff --git a/modules/expo-bluesky-swiss-army/src/PlatformInfo/index.web.ts b/modules/expo-bluesky-swiss-army/src/PlatformInfo/index.web.ts
new file mode 100644
index 000000000..c7ae6b7cd
--- /dev/null
+++ b/modules/expo-bluesky-swiss-army/src/PlatformInfo/index.web.ts
@@ -0,0 +1,6 @@
+export function getIsReducedMotionEnabled(): boolean {
+  if (typeof window === 'undefined') {
+    return false
+  }
+  return window.matchMedia('(prefers-reduced-motion: reduce)').matches
+}
diff --git a/patches/react-native-reanimated+3.11.0.patch b/patches/react-native-reanimated+3.11.0.patch
index 9147cf08e..a79a0ac08 100644
--- a/patches/react-native-reanimated+3.11.0.patch
+++ b/patches/react-native-reanimated+3.11.0.patch
@@ -207,31 +207,3 @@ index 88b3fdf..2488ebc 100644
 
          const { layout, entering, exiting, sharedTransitionTag } = this.props;
          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';
diff --git a/src/platform/detection.ts b/src/platform/detection.ts
index 0c0360a82..f00df0ee4 100644
--- a/src/platform/detection.ts
+++ b/src/platform/detection.ts
@@ -1,5 +1,4 @@
 import {Platform} from 'react-native'
-import {isReducedMotion} from 'react-native-reanimated'
 import {getLocales} from 'expo-localization'
 
 import {fixLegacyLanguageCode} from '#/locale/helpers'
@@ -21,5 +20,3 @@ export const deviceLocales = dedupArray(
     .map?.(locale => fixLegacyLanguageCode(locale.languageCode))
     .filter(code => typeof code === 'string'),
 ) as string[]
-
-export const prefersReducedMotion = isReducedMotion()
diff --git a/src/state/a11y.tsx b/src/state/a11y.tsx
index aefcfd1ec..08948267c 100644
--- a/src/state/a11y.tsx
+++ b/src/state/a11y.tsx
@@ -1,8 +1,8 @@
 import React from 'react'
 import {AccessibilityInfo} from 'react-native'
-import {isReducedMotion} from 'react-native-reanimated'
 
 import {isWeb} from '#/platform/detection'
+import {PlatformInfo} from '../../modules/expo-bluesky-swiss-army'
 
 const Context = React.createContext({
   reduceMotionEnabled: false,
@@ -15,7 +15,7 @@ export function useA11y() {
 
 export function Provider({children}: React.PropsWithChildren<{}>) {
   const [reduceMotionEnabled, setReduceMotionEnabled] = React.useState(() =>
-    isReducedMotion(),
+    PlatformInfo.getIsReducedMotionEnabled(),
   )
   const [screenReaderEnabled, setScreenReaderEnabled] = React.useState(false)
 
diff --git a/src/state/persisted/schema.ts b/src/state/persisted/schema.ts
index 88fc370a6..399a7e793 100644
--- a/src/state/persisted/schema.ts
+++ b/src/state/persisted/schema.ts
@@ -1,6 +1,7 @@
 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
 
@@ -128,7 +129,7 @@ export const defaults: Schema = {
   lastSelectedHomeFeed: undefined,
   pdsAddressHistory: [],
   disableHaptics: false,
-  disableAutoplay: prefersReducedMotion,
+  disableAutoplay: PlatformInfo.getIsReducedMotionEnabled(),
   kawaii: false,
   hasCheckedForStarterPack: false,
 }
diff --git a/src/view/screens/Storybook/Dialogs.tsx b/src/view/screens/Storybook/Dialogs.tsx
index ca2420fed..3a9f67de8 100644
--- a/src/view/screens/Storybook/Dialogs.tsx
+++ b/src/view/screens/Storybook/Dialogs.tsx
@@ -9,6 +9,7 @@ import {Button, ButtonText} from '#/components/Button'
 import * as Dialog from '#/components/Dialog'
 import * as Prompt from '#/components/Prompt'
 import {H3, P, Text} from '#/components/Typography'
+import {PlatformInfo} from '../../../../modules/expo-bluesky-swiss-army'
 
 export function Dialogs() {
   const scrollable = Dialog.useDialogControl()
@@ -17,6 +18,8 @@ export function Dialogs() {
   const testDialog = Dialog.useDialogControl()
   const {closeAllDialogs} = useDialogStateControlContext()
   const unmountTestDialog = Dialog.useDialogControl()
+  const [reducedMotionEnabled, setReducedMotionEnabled] =
+    React.useState<boolean>()
   const [shouldRenderUnmountTest, setShouldRenderUnmountTest] =
     React.useState(false)
   const unmountTestInterval = React.useRef<number>()
@@ -147,6 +150,22 @@ export function Dialogs() {
         <ButtonText>Open Shared Prefs Tester</ButtonText>
       </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.TitleText>This is a prompt</Prompt.TitleText>
         <Prompt.DescriptionText>