about summary refs log tree commit diff
path: root/patches
diff options
context:
space:
mode:
authorhailey <me@haileyok.com>2025-05-02 13:23:39 -0700
committerGitHub <noreply@github.com>2025-05-02 13:23:39 -0700
commit544f7befe0f7d3e61fb03365ec588a2ab3c5a17a (patch)
tree9d6276058aeeb44e77cba2b11bcc9e95cb8b7521 /patches
parent46ea3fdbeeab4e31657638955401145683738fbf (diff)
downloadvoidsky-544f7befe0f7d3e61fb03365ec588a2ab3c5a17a.tar.zst
bump it bop it upgrade it (rn 79/expo 53) (#8281)
* basic bumps

* more tweaking

* fix rn patch

* fix crop picker patch

* fix media library patch

* rm unnecessary patch

* fix notifications patch

* update bottomsheet

* Update withAppDelegateReferrer.js

* Delete withNoBundleCompression.js

* rm withNoBundleCompression plugin

* rm findLast shim

* metro package exports is enabled by default

* update react/react-dom/react-compiler

* fix reanimated issue

* vendor expo-ized emoji popup

* fix types

* hackfix view full thread

* Update EmojiPickerModule.podspec

* more upgrades

* fix multiformats package version

* add baseurl

* bump mmkv

* bumps

* update react-keyed-flatten-children

* bump locale packages

* fix emoji picker dark mode

* rn upgrades

* Revert "bump locale packages"

This reverts commit fc82f0f173032127dd7c18ed0316ae26f53db51d.

* upgrade testing-library

* rm test renderer

* update patch name minors

* rm findNodeHandle from tabbar

* only do scrollview tag thing on ios

* disable package exports

* update expo notifications handler

* memoize emoji picker styles

* fix tests, mock multiformats

* bump some dev deps with RC versions

* completely rearchitect toasts

* rm logs

* layout animation config for composer footer

* disable autolinking for patched libs

* undo lingui changes

* version bump from release candidate to 0.1

* update atproto deps

* rm @did-plc/server

* fix key issue (maybe)

* move URL polyfill to the polyfill file

* fix yarn lock

* upgrade to 53.0.3

* reanimated layout anim bug patch

* workletize a function that wasn't getting autoworkletized anymore (#8309)

* bump to expo 53.0.4

* bump RN to 0.79.2

* fix yarn lock ci

* Revert "completely rearchitect toasts"

This reverts commit 2e2fcaeeed527580a6c485718544b85e8b4f52b9.

* final upgrades

* chore: cleanup yarn lock

* prettier

---------

Co-authored-by: Samuel Newman <mozzius@protonmail.com>
Diffstat (limited to 'patches')
-rw-r--r--patches/expo-haptics+14.1.4.patch (renamed from patches/expo-haptics+14.0.1.patch)0
-rw-r--r--patches/expo-haptics+14.1.4.patch.md (renamed from patches/expo-haptics+14.0.0.md)0
-rw-r--r--patches/expo-image-manipulator+13.0.6.patch101
-rw-r--r--patches/expo-media-library+17.1.6.patch (renamed from patches/expo-media-library+17.0.6.patch)22
-rw-r--r--patches/expo-modules-core+2.3.12.patch (renamed from patches/expo-modules-core+2.2.3.patch)0
-rw-r--r--patches/expo-modules-core+2.3.12.patch.md (renamed from patches/expo-modules-core+2.1.2.md)0
-rw-r--r--patches/expo-notifications+0.29.14.patch169
-rw-r--r--patches/expo-notifications+0.31.1.patch992
-rw-r--r--patches/expo-notifications+0.31.1.patch.md (renamed from patches/expo-notifications+0.29.11.patch.md)0
-rw-r--r--patches/expo-updates+0.28.12.patch (renamed from patches/expo-updates+0.27.4.patch)0
-rw-r--r--patches/expo-updates+0.28.12.patch.md (renamed from patches/expo-updates+0.26.10.patch.md)0
-rw-r--r--patches/react-native+0.76.9.patch366
-rw-r--r--patches/react-native+0.79.2.patch119
-rw-r--r--patches/react-native+0.79.2.patch.md (renamed from patches/react-native+0.76.6.patch.md)4
-rw-r--r--patches/react-native-gesture-handler+2.25.0.patch (renamed from patches/react-native-gesture-handler+2.20.2.patch)0
-rw-r--r--patches/react-native-image-crop-picker+0.42.0.patch (renamed from patches/react-native-image-crop-picker+0.41.6.patch)19
-rw-r--r--patches/react-native-reanimated+3.17.5.patch44
-rw-r--r--patches/react-native-svg+15.11.2.patch (renamed from patches/react-native-svg+15.8.0.patch)0
18 files changed, 1176 insertions, 660 deletions
diff --git a/patches/expo-haptics+14.0.1.patch b/patches/expo-haptics+14.1.4.patch
index 9c7b9a666..9c7b9a666 100644
--- a/patches/expo-haptics+14.0.1.patch
+++ b/patches/expo-haptics+14.1.4.patch
diff --git a/patches/expo-haptics+14.0.0.md b/patches/expo-haptics+14.1.4.patch.md
index afa7395bc..afa7395bc 100644
--- a/patches/expo-haptics+14.0.0.md
+++ b/patches/expo-haptics+14.1.4.patch.md
diff --git a/patches/expo-image-manipulator+13.0.6.patch b/patches/expo-image-manipulator+13.0.6.patch
deleted file mode 100644
index 02d4d5fb9..000000000
--- a/patches/expo-image-manipulator+13.0.6.patch
+++ /dev/null
@@ -1,101 +0,0 @@
-diff --git a/node_modules/expo-image-manipulator/src/ImageManipulator.web.ts b/node_modules/expo-image-manipulator/src/ImageManipulator.web.ts
-new file mode 100644
-index 0000000..babbb3b
---- /dev/null
-+++ b/node_modules/expo-image-manipulator/src/ImageManipulator.web.ts
-@@ -0,0 +1,60 @@
-+import { useReleasingSharedObject } from 'expo-modules-core';
-+import { SharedRef } from 'expo-modules-core/types';
-+
-+import { Action, ImageResult, SaveFormat, SaveOptions } from './ImageManipulator.types';
-+import { ImageManipulatorContext } from './ImageManipulatorContext';
-+import ExpoImageManipulator from './NativeImageManipulatorModule';
-+import { validateArguments } from './validators';
-+
-+// @needsAudit
-+/**
-+ * Manipulate the image provided via `uri`. Available modifications are rotating, flipping (mirroring),
-+ * resizing and cropping. Each invocation results in a new file. With one invocation you can provide
-+ * a set of actions to perform over the image. Overwriting the source file would not have an effect
-+ * in displaying the result as images are cached.
-+ * @param uri URI of the file to manipulate. Should be on the local file system or a base64 data URI.
-+ * @param actions An array of objects representing manipulation options. Each object should have
-+ * __only one__ of the keys that corresponds to specific transformation.
-+ * @param saveOptions A map defining how modified image should be saved.
-+ * @return Promise which fulfils with [`ImageResult`](#imageresult) object.
-+ * @deprecated It has been replaced by the new, contextual and object-oriented API.
-+ * Use [`ImageManipulator.manipulate`](#manipulateuri) or [`useImageManipulator`](#useimagemanipulatoruri) instead.
-+ */
-+export async function manipulateAsync(
-+  uri: string,
-+  actions: Action[] = [],
-+  saveOptions: SaveOptions = {}
-+): Promise<ImageResult> {
-+  validateArguments(uri, actions, saveOptions);
-+
-+  const { format = SaveFormat.JPEG, ...rest } = saveOptions;
-+  const context = ExpoImageManipulator.manipulate(uri);
-+
-+  for (const action of actions) {
-+    if ('resize' in action) {
-+      context.resize(action.resize);
-+    } else if ('rotate' in action) {
-+      context.rotate(action.rotate);
-+    } else if ('flip' in action) {
-+      context.flip(action.flip);
-+    } else if ('crop' in action) {
-+      context.crop(action.crop);
-+    } else if ('extent' in action && context.extent) {
-+      context.extent(action.extent);
-+    }
-+  }
-+  const image = await context.renderAsync(saveOptions.compress);
-+  const result = await image.saveAsync({ format, ...rest });
-+
-+  // These shared objects will not be used anymore, so free up some memory.
-+  context.release();
-+  image.release();
-+
-+  return result;
-+}
-+
-+export function useImageManipulator(source: string | SharedRef<'image'>): ImageManipulatorContext {
-+  return useReleasingSharedObject(() => ExpoImageManipulator.manipulate(source), [source]);
-+}
-+
-+export { ExpoImageManipulator as ImageManipulator };
-diff --git a/node_modules/expo-image-manipulator/src/ImageManipulatorContext.ts b/node_modules/expo-image-manipulator/src/ImageManipulatorContext.ts
-index 120d8d3..f8aa49c 100644
---- a/node_modules/expo-image-manipulator/src/ImageManipulatorContext.ts
-+++ b/node_modules/expo-image-manipulator/src/ImageManipulatorContext.ts
-@@ -52,7 +52,7 @@ export declare class ImageManipulatorContext extends SharedObject {
-   /**
-    * Awaits for all manipulation tasks to finish and resolves with a reference to the resulted native image.
-    */
--  renderAsync(): Promise<ImageRef>;
-+  renderAsync(compress?: number): Promise<ImageRef>;
- }
- 
- export default ExpoImageManipulator.Context as typeof ImageManipulatorContext;
-diff --git a/node_modules/expo-image-manipulator/src/web/ImageManipulatorContext.web.ts b/node_modules/expo-image-manipulator/src/web/ImageManipulatorContext.web.ts
-index 428848c..363a57a 100644
---- a/node_modules/expo-image-manipulator/src/web/ImageManipulatorContext.web.ts
-+++ b/node_modules/expo-image-manipulator/src/web/ImageManipulatorContext.web.ts
-@@ -41,7 +41,7 @@ export default class ImageManipulatorContext extends SharedObject {
-     return this;
-   }
- 
--  async renderAsync(): Promise<ImageManipulatorImageRef> {
-+  async renderAsync(compress?: number): Promise<ImageManipulatorImageRef> {
-     const canvas = await this.currentTask;
- 
-     return new Promise((resolve) => {
-@@ -49,7 +49,7 @@ export default class ImageManipulatorContext extends SharedObject {
-         const url = blob ? URL.createObjectURL(blob) : canvas.toDataURL();
- 
-         resolve(new ImageManipulatorImageRef(url, canvas.width, canvas.height));
--      });
-+      }, typeof compress === 'number' ? 'image/jpeg' : undefined, compress);
-     });
-   }
- 
diff --git a/patches/expo-media-library+17.0.6.patch b/patches/expo-media-library+17.1.6.patch
index 7ef57f768..4fa853ec3 100644
--- a/patches/expo-media-library+17.0.6.patch
+++ b/patches/expo-media-library+17.1.6.patch
@@ -1,19 +1,19 @@
 diff --git a/node_modules/expo-media-library/android/src/main/java/expo/modules/medialibrary/MediaLibraryModule.kt b/node_modules/expo-media-library/android/src/main/java/expo/modules/medialibrary/MediaLibraryModule.kt
-index 64e6efe..e61485e 100644
+index f1255e8..a9b49e5 100644
 --- a/node_modules/expo-media-library/android/src/main/java/expo/modules/medialibrary/MediaLibraryModule.kt
 +++ b/node_modules/expo-media-library/android/src/main/java/expo/modules/medialibrary/MediaLibraryModule.kt
-@@ -111,12 +111,12 @@ class MediaLibraryModule : Module() {
+@@ -112,11 +112,9 @@ class MediaLibraryModule : Module() {
      }
  
-     AsyncFunction("createAssetAsync") { localUri: String, promise: Promise ->
+     AsyncFunction("createAssetAsync") { localUri: String, albumId: String?, promise: Promise ->
 -      throwUnlessPermissionsGranted {
-+      //throwUnlessPermissionsGranted {
-         withModuleScope(promise) {
-           CreateAsset(context, localUri, promise)
-             .execute()
-         }
--      }
-+      //}
+-        withModuleScope(promise) {
+-          CreateAssetWithAlbumId(context, localUri, promise, true, albumId)
+-            .execute()
+-        }
++      withModuleScope(promise) {
++        CreateAssetWithAlbumId(context, localUri, promise, true, albumId)
++          .execute()
+       }
      }
  
-     AsyncFunction("addAssetsToAlbumAsync") { assetsId: List<String>, albumId: String, copyToAlbum: Boolean, promise: Promise ->
diff --git a/patches/expo-modules-core+2.2.3.patch b/patches/expo-modules-core+2.3.12.patch
index f3d9bfd14..f3d9bfd14 100644
--- a/patches/expo-modules-core+2.2.3.patch
+++ b/patches/expo-modules-core+2.3.12.patch
diff --git a/patches/expo-modules-core+2.1.2.md b/patches/expo-modules-core+2.3.12.patch.md
index a71324c19..a71324c19 100644
--- a/patches/expo-modules-core+2.1.2.md
+++ b/patches/expo-modules-core+2.3.12.patch.md
diff --git a/patches/expo-notifications+0.29.14.patch b/patches/expo-notifications+0.29.14.patch
deleted file mode 100644
index dd70cc781..000000000
--- a/patches/expo-notifications+0.29.14.patch
+++ /dev/null
@@ -1,169 +0,0 @@
-diff --git a/node_modules/expo-notifications/android/build.gradle b/node_modules/expo-notifications/android/build.gradle
-index 13bffbb..5ebbede 100644
---- a/node_modules/expo-notifications/android/build.gradle
-+++ b/node_modules/expo-notifications/android/build.gradle
-@@ -46,6 +46,7 @@ dependencies {
-   implementation 'com.google.firebase:firebase-messaging:24.0.1'
- 
-   implementation 'me.leolin:ShortcutBadger:1.1.22@aar'
-+  implementation project(':expo-background-notification-handler')
- 
-   if (project.findProject(':expo-modules-test-core')) {
-     testImplementation project(':expo-modules-test-core')
-diff --git a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/interfaces/INotificationContent.kt b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/interfaces/INotificationContent.kt
-index 7b99e6c..45a450d 100644
---- a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/interfaces/INotificationContent.kt
-+++ b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/interfaces/INotificationContent.kt
-@@ -15,6 +15,7 @@ import org.json.JSONObject
-  * This interface exists to provide a common API for both classes.
-  * */
- interface INotificationContent : Parcelable {
-+  val channelId: String?
-   val title: String?
-   val text: String?
-   val subText: String?
-diff --git a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/NotificationContent.java b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/NotificationContent.java
-index 191b64e..fe8b3c5 100644
---- a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/NotificationContent.java
-+++ b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/NotificationContent.java
-@@ -35,6 +35,7 @@ import kotlin.coroutines.Continuation;
-  * Refactoring this class may require a migration strategy for the data stored in SharedPreferences.
-  */
- public class NotificationContent implements Parcelable, Serializable, INotificationContent {
-+  private String mChannelId;
-   private String mTitle;
-   private String mText;
-   private String mSubtitle;
-@@ -65,6 +66,11 @@ public class NotificationContent implements Parcelable, Serializable, INotificat
-     }
-   };
- 
-+  @Nullable
-+  public String getChannelId() {
-+    return mChannelId;
-+  }
-+
-   @Nullable
-   public String getTitle() {
-     return mTitle;
-@@ -158,6 +164,7 @@ public class NotificationContent implements Parcelable, Serializable, INotificat
-   }
- 
-   protected NotificationContent(Parcel in) {
-+    mChannelId = in.readString();
-     mTitle = in.readString();
-     mText = in.readString();
-     mSubtitle = in.readString();
-@@ -183,6 +190,7 @@ public class NotificationContent implements Parcelable, Serializable, INotificat
- 
-   @Override
-   public void writeToParcel(Parcel dest, int flags) {
-+    dest.writeString(mChannelId);
-     dest.writeString(mTitle);
-     dest.writeString(mText);
-     dest.writeString(mSubtitle);
-@@ -203,6 +211,7 @@ public class NotificationContent implements Parcelable, Serializable, INotificat
-   private static final long serialVersionUID = 397666843266836802L;
- 
-   private void writeObject(java.io.ObjectOutputStream out) throws IOException {
-+    out.writeObject(mChannelId);
-     out.writeObject(mTitle);
-     out.writeObject(mText);
-     out.writeObject(mSubtitle);
-@@ -285,6 +294,11 @@ public class NotificationContent implements Parcelable, Serializable, INotificat
-       useDefaultVibrationPattern();
-     }
- 
-+    public Builder setChannelId(String channelId) {
-+      content.mChannelId = channelId;
-+      return this;
-+    }
-+
-     public Builder setTitle(String title) {
-       content.mTitle = title;
-       return this;
-diff --git a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/NotificationData.kt b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/NotificationData.kt
-index 39b5aad..e50797d 100644
---- a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/NotificationData.kt
-+++ b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/NotificationData.kt
-@@ -11,6 +11,9 @@ import org.json.JSONObject
- * */
- @JvmInline
- value class NotificationData(private val data: Map<String, String>) {
-+  val channelId: String?
-+    get() = data["channelId"]
-+
-   val title: String?
-     get() = data["title"]
- 
-diff --git a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/RemoteNotificationContent.kt b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/RemoteNotificationContent.kt
-index d2cc6cf..6a48ff2 100644
---- a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/RemoteNotificationContent.kt
-+++ b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/RemoteNotificationContent.kt
-@@ -31,6 +31,8 @@ class RemoteNotificationContent(private val remoteMessage: RemoteMessage) : INot
-     return remoteMessage.notification?.imageUrl != null
-   }
- 
-+  override val channelId = remoteMessage.notification?.channelId ?: notificationData.channelId
-+
-   override val title = remoteMessage.notification?.title ?: notificationData.title
- 
-   override val text = remoteMessage.notification?.body ?: notificationData.message
-diff --git a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/presentation/builders/ExpoNotificationBuilder.kt b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/presentation/builders/ExpoNotificationBuilder.kt
-index 8ca6ec5..57c3599 100644
---- a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/presentation/builders/ExpoNotificationBuilder.kt
-+++ b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/presentation/builders/ExpoNotificationBuilder.kt
-@@ -101,6 +101,9 @@ open class ExpoNotificationBuilder(
-     builder.setOngoing(content.isSticky)
- 
-     // see "Notification anatomy" https://developer.android.com/develop/ui/views/notifications#Templates
-+    content.channelId?.let {
-+      builder.setChannelId(it)
-+    }
-     builder.setContentTitle(content.title)
-     builder.setContentText(content.text)
-     builder.setSubText(content.subText)
-diff --git a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/service/delegates/FirebaseMessagingDelegate.kt b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/service/delegates/FirebaseMessagingDelegate.kt
-index 9f22441..5f92f80 100644
---- a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/service/delegates/FirebaseMessagingDelegate.kt
-+++ b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/service/delegates/FirebaseMessagingDelegate.kt
-@@ -2,6 +2,9 @@ package expo.modules.notifications.service.delegates
- 
- import android.content.Context
- import com.google.firebase.messaging.RemoteMessage
-+import expo.modules.backgroundnotificationhandler.BackgroundNotificationHandler
-+import expo.modules.backgroundnotificationhandler.BackgroundNotificationHandlerInterface
-+import expo.modules.backgroundnotificationhandler.ExpoBackgroundNotificationHandlerModule
- import expo.modules.interfaces.taskManager.TaskServiceProviderHelper
- import expo.modules.notifications.notifications.RemoteMessageSerializer
- import expo.modules.notifications.notifications.background.BackgroundRemoteNotificationTaskConsumer
-@@ -17,7 +20,8 @@ import expo.modules.notifications.tokens.interfaces.FirebaseTokenListener
- import java.lang.ref.WeakReference
- import java.util.*
- 
--open class FirebaseMessagingDelegate(protected val context: Context) : FirebaseMessagingDelegate {
-+open class FirebaseMessagingDelegate(protected val context: Context) : FirebaseMessagingDelegate,
-+  BackgroundNotificationHandlerInterface {
-   companion object {
-     // Unfortunately we cannot save state between instances of a service other way
-     // than by static properties. Fortunately, using weak references we can
-@@ -94,8 +98,17 @@ open class FirebaseMessagingDelegate(protected val context: Context) : FirebaseM
-     DebugLogging.logRemoteMessage("FirebaseMessagingDelegate.onMessageReceived: message", remoteMessage)
-     val notification = createNotification(remoteMessage)
-     DebugLogging.logNotification("FirebaseMessagingDelegate.onMessageReceived: notification", notification)
--    NotificationsService.receive(context, notification)
--    runTaskManagerTasks(remoteMessage)
-+
-+    if (!ExpoBackgroundNotificationHandlerModule.isForegrounded) {
-+      BackgroundNotificationHandler(context, this).handleMessage(remoteMessage)
-+    } else {
-+      showMessage(remoteMessage)
-+      runTaskManagerTasks(remoteMessage)
-+    }
-+  }
-+
-+  override fun showMessage(remoteMessage: RemoteMessage) {
-+    NotificationsService.receive(context, createNotification(remoteMessage))
-   }
- 
-   private fun runTaskManagerTasks(remoteMessage: RemoteMessage) {
diff --git a/patches/expo-notifications+0.31.1.patch b/patches/expo-notifications+0.31.1.patch
new file mode 100644
index 000000000..56e639a26
--- /dev/null
+++ b/patches/expo-notifications+0.31.1.patch
@@ -0,0 +1,992 @@
+diff --git a/node_modules/expo-notifications/android/.gradle/8.10/checksums/checksums.lock b/node_modules/expo-notifications/android/.gradle/8.10/checksums/checksums.lock
+new file mode 100644
+index 0000000..883ef6a
+Binary files /dev/null and b/node_modules/expo-notifications/android/.gradle/8.10/checksums/checksums.lock differ
+diff --git a/node_modules/expo-notifications/android/.gradle/8.10/dependencies-accessors/gc.properties b/node_modules/expo-notifications/android/.gradle/8.10/dependencies-accessors/gc.properties
+new file mode 100644
+index 0000000..e69de29
+diff --git a/node_modules/expo-notifications/android/.gradle/8.10/fileChanges/last-build.bin b/node_modules/expo-notifications/android/.gradle/8.10/fileChanges/last-build.bin
+new file mode 100644
+index 0000000..f76dd23
+Binary files /dev/null and b/node_modules/expo-notifications/android/.gradle/8.10/fileChanges/last-build.bin differ
+diff --git a/node_modules/expo-notifications/android/.gradle/8.10/fileHashes/fileHashes.lock b/node_modules/expo-notifications/android/.gradle/8.10/fileHashes/fileHashes.lock
+new file mode 100644
+index 0000000..774caf7
+Binary files /dev/null and b/node_modules/expo-notifications/android/.gradle/8.10/fileHashes/fileHashes.lock differ
+diff --git a/node_modules/expo-notifications/android/.gradle/8.10/gc.properties b/node_modules/expo-notifications/android/.gradle/8.10/gc.properties
+new file mode 100644
+index 0000000..e69de29
+diff --git a/node_modules/expo-notifications/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/node_modules/expo-notifications/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock
+new file mode 100644
+index 0000000..a3c1514
+Binary files /dev/null and b/node_modules/expo-notifications/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock differ
+diff --git a/node_modules/expo-notifications/android/.gradle/buildOutputCleanup/cache.properties b/node_modules/expo-notifications/android/.gradle/buildOutputCleanup/cache.properties
+new file mode 100644
+index 0000000..0e5b4da
+--- /dev/null
++++ b/node_modules/expo-notifications/android/.gradle/buildOutputCleanup/cache.properties
+@@ -0,0 +1,2 @@
++#Thu Apr 24 20:44:36 PDT 2025
++gradle.version=8.10
+diff --git a/node_modules/expo-notifications/android/.gradle/config.properties b/node_modules/expo-notifications/android/.gradle/config.properties
+new file mode 100644
+index 0000000..0bd71c6
+--- /dev/null
++++ b/node_modules/expo-notifications/android/.gradle/config.properties
+@@ -0,0 +1,2 @@
++#Thu Apr 24 20:44:32 PDT 2025
++java.home=/Applications/Android Studio.app/Contents/jbr/Contents/Home
+diff --git a/node_modules/expo-notifications/android/.gradle/vcs-1/gc.properties b/node_modules/expo-notifications/android/.gradle/vcs-1/gc.properties
+new file mode 100644
+index 0000000..e69de29
+diff --git a/node_modules/expo-notifications/android/.idea/.gitignore b/node_modules/expo-notifications/android/.idea/.gitignore
+new file mode 100644
+index 0000000..26d3352
+--- /dev/null
++++ b/node_modules/expo-notifications/android/.idea/.gitignore
+@@ -0,0 +1,3 @@
++# Default ignored files
++/shelf/
++/workspace.xml
+diff --git a/node_modules/expo-notifications/android/.idea/AndroidProjectSystem.xml b/node_modules/expo-notifications/android/.idea/AndroidProjectSystem.xml
+new file mode 100644
+index 0000000..4a53bee
+--- /dev/null
++++ b/node_modules/expo-notifications/android/.idea/AndroidProjectSystem.xml
+@@ -0,0 +1,6 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<project version="4">
++  <component name="AndroidProjectSystem">
++    <option name="providerId" value="com.android.tools.idea.GradleProjectSystem" />
++  </component>
++</project>
+\ No newline at end of file
+diff --git a/node_modules/expo-notifications/android/.idea/caches/deviceStreaming.xml b/node_modules/expo-notifications/android/.idea/caches/deviceStreaming.xml
+new file mode 100644
+index 0000000..9e9ba09
+--- /dev/null
++++ b/node_modules/expo-notifications/android/.idea/caches/deviceStreaming.xml
+@@ -0,0 +1,607 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<project version="4">
++  <component name="DeviceStreaming">
++    <option name="deviceSelectionList">
++      <list>
++        <PersistentDeviceSelectionData>
++          <option name="api" value="27" />
++          <option name="brand" value="DOCOMO" />
++          <option name="codename" value="F01L" />
++          <option name="id" value="F01L" />
++          <option name="labId" value="google" />
++          <option name="manufacturer" value="FUJITSU" />
++          <option name="name" value="F-01L" />
++          <option name="screenDensity" value="360" />
++          <option name="screenX" value="720" />
++          <option name="screenY" value="1280" />
++        </PersistentDeviceSelectionData>
++        <PersistentDeviceSelectionData>
++          <option name="api" value="34" />
++          <option name="brand" value="OnePlus" />
++          <option name="codename" value="OP5552L1" />
++          <option name="id" value="OP5552L1" />
++          <option name="labId" value="google" />
++          <option name="manufacturer" value="OnePlus" />
++          <option name="name" value="CPH2415" />
++          <option name="screenDensity" value="480" />
++          <option name="screenX" value="1080" />
++          <option name="screenY" value="2412" />
++        </PersistentDeviceSelectionData>
++        <PersistentDeviceSelectionData>
++          <option name="api" value="34" />
++          <option name="brand" value="OPPO" />
++          <option name="codename" value="OP573DL1" />
++          <option name="id" value="OP573DL1" />
++          <option name="labId" value="google" />
++          <option name="manufacturer" value="OPPO" />
++          <option name="name" value="CPH2557" />
++          <option name="screenDensity" value="480" />
++          <option name="screenX" value="1080" />
++          <option name="screenY" value="2400" />
++        </PersistentDeviceSelectionData>
++        <PersistentDeviceSelectionData>
++          <option name="api" value="28" />
++          <option name="brand" value="DOCOMO" />
++          <option name="codename" value="SH-01L" />
++          <option name="id" value="SH-01L" />
++          <option name="labId" value="google" />
++          <option name="manufacturer" value="SHARP" />
++          <option name="name" value="AQUOS sense2 SH-01L" />
++          <option name="screenDensity" value="480" />
++          <option name="screenX" value="1080" />
++          <option name="screenY" value="2160" />
++        </PersistentDeviceSelectionData>
++        <PersistentDeviceSelectionData>
++          <option name="api" value="34" />
++          <option name="brand" value="Lenovo" />
++          <option name="codename" value="TB370FU" />
++          <option name="formFactor" value="Tablet" />
++          <option name="id" value="TB370FU" />
++          <option name="labId" value="google" />
++          <option name="manufacturer" value="Lenovo" />
++          <option name="name" value="Tab P12" />
++          <option name="screenDensity" value="340" />
++          <option name="screenX" value="1840" />
++          <option name="screenY" value="2944" />
++        </PersistentDeviceSelectionData>
++        <PersistentDeviceSelectionData>
++          <option name="api" value="34" />
++          <option name="brand" value="samsung" />
++          <option name="codename" value="a15" />
++          <option name="id" value="a15" />
++          <option name="labId" value="google" />
++          <option name="manufacturer" value="Samsung" />
++          <option name="name" value="A15" />
++          <option name="screenDensity" value="450" />
++          <option name="screenX" value="1080" />
++          <option name="screenY" value="2340" />
++        </PersistentDeviceSelectionData>
++        <PersistentDeviceSelectionData>
++          <option name="api" value="34" />
++          <option name="brand" value="samsung" />
++          <option name="codename" value="a35x" />
++          <option name="id" value="a35x" />
++          <option name="labId" value="google" />
++          <option name="manufacturer" value="Samsung" />
++          <option name="name" value="A35" />
++          <option name="screenDensity" value="450" />
++          <option name="screenX" value="1080" />
++          <option name="screenY" value="2340" />
++        </PersistentDeviceSelectionData>
++        <PersistentDeviceSelectionData>
++          <option name="api" value="31" />
++          <option name="brand" value="samsung" />
++          <option name="codename" value="a51" />
++          <option name="id" value="a51" />
++          <option name="labId" value="google" />
++          <option name="manufacturer" value="Samsung" />
++          <option name="name" value="Galaxy A51" />
++          <option name="screenDensity" value="420" />
++          <option name="screenX" value="1080" />
++          <option name="screenY" value="2400" />
++        </PersistentDeviceSelectionData>
++        <PersistentDeviceSelectionData>
++          <option name="api" value="34" />
++          <option name="brand" value="google" />
++          <option name="codename" value="akita" />
++          <option name="id" value="akita" />
++          <option name="labId" value="google" />
++          <option name="manufacturer" value="Google" />
++          <option name="name" value="Pixel 8a" />
++          <option name="screenDensity" value="420" />
++          <option name="screenX" value="1080" />
++          <option name="screenY" value="2400" />
++        </PersistentDeviceSelectionData>
++        <PersistentDeviceSelectionData>
++          <option name="api" value="34" />
++          <option name="brand" value="motorola" />
++          <option name="codename" value="arcfox" />
++          <option name="id" value="arcfox" />
++          <option name="labId" value="google" />
++          <option name="manufacturer" value="Motorola" />
++          <option name="name" value="razr plus 2024" />
++          <option name="screenDensity" value="360" />
++          <option name="screenX" value="1080" />
++          <option name="screenY" value="1272" />
++        </PersistentDeviceSelectionData>
++        <PersistentDeviceSelectionData>
++          <option name="api" value="33" />
++          <option name="brand" value="motorola" />
++          <option name="codename" value="austin" />
++          <option name="id" value="austin" />
++          <option name="labId" value="google" />
++          <option name="manufacturer" value="Motorola" />
++          <option name="name" value="moto g 5G (2022)" />
++          <option name="screenDensity" value="280" />
++          <option name="screenX" value="720" />
++          <option name="screenY" value="1600" />
++        </PersistentDeviceSelectionData>
++        <PersistentDeviceSelectionData>
++          <option name="api" value="33" />
++          <option name="brand" value="samsung" />
++          <option name="codename" value="b0q" />
++          <option name="id" value="b0q" />
++          <option name="labId" value="google" />
++          <option name="manufacturer" value="Samsung" />
++          <option name="name" value="Galaxy S22 Ultra" />
++          <option name="screenDensity" value="600" />
++          <option name="screenX" value="1440" />
++          <option name="screenY" value="3088" />
++        </PersistentDeviceSelectionData>
++        <PersistentDeviceSelectionData>
++          <option name="api" value="32" />
++          <option name="brand" value="google" />
++          <option name="codename" value="bluejay" />
++          <option name="id" value="bluejay" />
++          <option name="labId" value="google" />
++          <option name="manufacturer" value="Google" />
++          <option name="name" value="Pixel 6a" />
++          <option name="screenDensity" value="420" />
++          <option name="screenX" value="1080" />
++          <option name="screenY" value="2400" />
++        </PersistentDeviceSelectionData>
++        <PersistentDeviceSelectionData>
++          <option name="api" value="34" />
++          <option name="brand" value="google" />
++          <option name="codename" value="caiman" />
++          <option name="id" value="caiman" />
++          <option name="labId" value="google" />
++          <option name="manufacturer" value="Google" />
++          <option name="name" value="Pixel 9 Pro" />
++          <option name="screenDensity" value="360" />
++          <option name="screenX" value="960" />
++          <option name="screenY" value="2142" />
++        </PersistentDeviceSelectionData>
++        <PersistentDeviceSelectionData>
++          <option name="api" value="34" />
++          <option name="brand" value="google" />
++          <option name="codename" value="comet" />
++          <option name="default" value="true" />
++          <option name="id" value="comet" />
++          <option name="labId" value="google" />
++          <option name="manufacturer" value="Google" />
++          <option name="name" value="Pixel 9 Pro Fold" />
++          <option name="screenDensity" value="390" />
++          <option name="screenX" value="2076" />
++          <option name="screenY" value="2152" />
++        </PersistentDeviceSelectionData>
++        <PersistentDeviceSelectionData>
++          <option name="api" value="29" />
++          <option name="brand" value="samsung" />
++          <option name="codename" value="crownqlteue" />
++          <option name="id" value="crownqlteue" />
++          <option name="labId" value="google" />
++          <option name="manufacturer" value="Samsung" />
++          <option name="name" value="Galaxy Note9" />
++          <option name="screenDensity" value="420" />
++          <option name="screenX" value="2220" />
++          <option name="screenY" value="1080" />
++        </PersistentDeviceSelectionData>
++        <PersistentDeviceSelectionData>
++          <option name="api" value="34" />
++          <option name="brand" value="samsung" />
++          <option name="codename" value="dm2q" />
++          <option name="id" value="dm2q" />
++          <option name="labId" value="google" />
++          <option name="manufacturer" value="Samsung" />
++          <option name="name" value="S23 Plus" />
++          <option name="screenDensity" value="450" />
++          <option name="screenX" value="1080" />
++          <option name="screenY" value="2340" />
++        </PersistentDeviceSelectionData>
++        <PersistentDeviceSelectionData>
++          <option name="api" value="34" />
++          <option name="brand" value="samsung" />
++          <option name="codename" value="dm3q" />
++          <option name="id" value="dm3q" />
++          <option name="labId" value="google" />
++          <option name="manufacturer" value="Samsung" />
++          <option name="name" value="Galaxy S23 Ultra" />
++          <option name="screenDensity" value="600" />
++          <option name="screenX" value="1440" />
++          <option name="screenY" value="3088" />
++        </PersistentDeviceSelectionData>
++        <PersistentDeviceSelectionData>
++          <option name="api" value="34" />
++          <option name="brand" value="samsung" />
++          <option name="codename" value="e1q" />
++          <option name="default" value="true" />
++          <option name="id" value="e1q" />
++          <option name="labId" value="google" />
++          <option name="manufacturer" value="Samsung" />
++          <option name="name" value="Galaxy S24" />
++          <option name="screenDensity" value="480" />
++          <option name="screenX" value="1080" />
++          <option name="screenY" value="2340" />
++        </PersistentDeviceSelectionData>
++        <PersistentDeviceSelectionData>
++          <option name="api" value="34" />
++          <option name="brand" value="samsung" />
++          <option name="codename" value="e3q" />
++          <option name="id" value="e3q" />
++          <option name="labId" value="google" />
++          <option name="manufacturer" value="Samsung" />
++          <option name="name" value="Galaxy S24 Ultra" />
++          <option name="screenDensity" value="450" />
++          <option name="screenX" value="1440" />
++          <option name="screenY" value="3120" />
++        </PersistentDeviceSelectionData>
++        <PersistentDeviceSelectionData>
++          <option name="api" value="33" />
++          <option name="brand" value="google" />
++          <option name="codename" value="eos" />
++          <option name="id" value="eos" />
++          <option name="labId" value="google" />
++          <option name="manufacturer" value="Google" />
++          <option name="name" value="Eos" />
++          <option name="screenDensity" value="320" />
++          <option name="screenX" value="384" />
++          <option name="screenY" value="384" />
++        </PersistentDeviceSelectionData>
++        <PersistentDeviceSelectionData>
++          <option name="api" value="33" />
++          <option name="brand" value="google" />
++          <option name="codename" value="felix" />
++          <option name="id" value="felix" />
++          <option name="labId" value="google" />
++          <option name="manufacturer" value="Google" />
++          <option name="name" value="Pixel Fold" />
++          <option name="screenDensity" value="420" />
++          <option name="screenX" value="2208" />
++          <option name="screenY" value="1840" />
++        </PersistentDeviceSelectionData>
++        <PersistentDeviceSelectionData>
++          <option name="api" value="34" />
++          <option name="brand" value="google" />
++          <option name="codename" value="felix" />
++          <option name="id" value="felix" />
++          <option name="labId" value="google" />
++          <option name="manufacturer" value="Google" />
++          <option name="name" value="Pixel Fold" />
++          <option name="screenDensity" value="420" />
++          <option name="screenX" value="2208" />
++          <option name="screenY" value="1840" />
++        </PersistentDeviceSelectionData>
++        <PersistentDeviceSelectionData>
++          <option name="api" value="33" />
++          <option name="brand" value="google" />
++          <option name="codename" value="felix_camera" />
++          <option name="id" value="felix_camera" />
++          <option name="labId" value="google" />
++          <option name="manufacturer" value="Google" />
++          <option name="name" value="Pixel Fold (Camera-enabled)" />
++          <option name="screenDensity" value="420" />
++          <option name="screenX" value="2208" />
++          <option name="screenY" value="1840" />
++        </PersistentDeviceSelectionData>
++        <PersistentDeviceSelectionData>
++          <option name="api" value="34" />
++          <option name="brand" value="motorola" />
++          <option name="codename" value="fogona" />
++          <option name="id" value="fogona" />
++          <option name="labId" value="google" />
++          <option name="manufacturer" value="Motorola" />
++          <option name="name" value="moto g play - 2024" />
++          <option name="screenDensity" value="280" />
++          <option name="screenX" value="720" />
++          <option name="screenY" value="1600" />
++        </PersistentDeviceSelectionData>
++        <PersistentDeviceSelectionData>
++          <option name="api" value="34" />
++          <option name="brand" value="samsung" />
++          <option name="codename" value="g0q" />
++          <option name="id" value="g0q" />
++          <option name="labId" value="google" />
++          <option name="manufacturer" value="Samsung" />
++          <option name="name" value="SM-S906U1" />
++          <option name="screenDensity" value="450" />
++          <option name="screenX" value="1080" />
++          <option name="screenY" value="2340" />
++        </PersistentDeviceSelectionData>
++        <PersistentDeviceSelectionData>
++          <option name="api" value="34" />
++          <option name="brand" value="samsung" />
++          <option name="codename" value="gta9pwifi" />
++          <option name="id" value="gta9pwifi" />
++          <option name="labId" value="google" />
++          <option name="manufacturer" value="Samsung" />
++          <option name="name" value="SM-X210" />
++          <option name="screenDensity" value="240" />
++          <option name="screenX" value="1200" />
++          <option name="screenY" value="1920" />
++        </PersistentDeviceSelectionData>
++        <PersistentDeviceSelectionData>
++          <option name="api" value="34" />
++          <option name="brand" value="samsung" />
++          <option name="codename" value="gts7xllite" />
++          <option name="id" value="gts7xllite" />
++          <option name="labId" value="google" />
++          <option name="manufacturer" value="Samsung" />
++          <option name="name" value="SM-T738U" />
++          <option name="screenDensity" value="340" />
++          <option name="screenX" value="1600" />
++          <option name="screenY" value="2560" />
++        </PersistentDeviceSelectionData>
++        <PersistentDeviceSelectionData>
++          <option name="api" value="33" />
++          <option name="brand" value="samsung" />
++          <option name="codename" value="gts8uwifi" />
++          <option name="formFactor" value="Tablet" />
++          <option name="id" value="gts8uwifi" />
++          <option name="labId" value="google" />
++          <option name="manufacturer" value="Samsung" />
++          <option name="name" value="Galaxy Tab S8 Ultra" />
++          <option name="screenDensity" value="320" />
++          <option name="screenX" value="1848" />
++          <option name="screenY" value="2960" />
++        </PersistentDeviceSelectionData>
++        <PersistentDeviceSelectionData>
++          <option name="api" value="34" />
++          <option name="brand" value="samsung" />
++          <option name="codename" value="gts8wifi" />
++          <option name="formFactor" value="Tablet" />
++          <option name="id" value="gts8wifi" />
++          <option name="labId" value="google" />
++          <option name="manufacturer" value="Samsung" />
++          <option name="name" value="Galaxy Tab S8" />
++          <option name="screenDensity" value="274" />
++          <option name="screenX" value="1600" />
++          <option name="screenY" value="2560" />
++        </PersistentDeviceSelectionData>
++        <PersistentDeviceSelectionData>
++          <option name="api" value="34" />
++          <option name="brand" value="samsung" />
++          <option name="codename" value="gts9fe" />
++          <option name="id" value="gts9fe" />
++          <option name="labId" value="google" />
++          <option name="manufacturer" value="Samsung" />
++          <option name="name" value="Galaxy Tab S9 FE 5G" />
++          <option name="screenDensity" value="280" />
++          <option name="screenX" value="1440" />
++          <option name="screenY" value="2304" />
++        </PersistentDeviceSelectionData>
++        <PersistentDeviceSelectionData>
++          <option name="api" value="34" />
++          <option name="brand" value="google" />
++          <option name="codename" value="husky" />
++          <option name="id" value="husky" />
++          <option name="labId" value="google" />
++          <option name="manufacturer" value="Google" />
++          <option name="name" value="Pixel 8 Pro" />
++          <option name="screenDensity" value="390" />
++          <option name="screenX" value="1008" />
++          <option name="screenY" value="2244" />
++        </PersistentDeviceSelectionData>
++        <PersistentDeviceSelectionData>
++          <option name="api" value="30" />
++          <option name="brand" value="motorola" />
++          <option name="codename" value="java" />
++          <option name="id" value="java" />
++          <option name="labId" value="google" />
++          <option name="manufacturer" value="Motorola" />
++          <option name="name" value="G20" />
++          <option name="screenDensity" value="280" />
++          <option name="screenX" value="720" />
++          <option name="screenY" value="1600" />
++        </PersistentDeviceSelectionData>
++        <PersistentDeviceSelectionData>
++          <option name="api" value="34" />
++          <option name="brand" value="google" />
++          <option name="codename" value="komodo" />
++          <option name="id" value="komodo" />
++          <option name="labId" value="google" />
++          <option name="manufacturer" value="Google" />
++          <option name="name" value="Pixel 9 Pro XL" />
++          <option name="screenDensity" value="360" />
++          <option name="screenX" value="1008" />
++          <option name="screenY" value="2244" />
++        </PersistentDeviceSelectionData>
++        <PersistentDeviceSelectionData>
++          <option name="api" value="33" />
++          <option name="brand" value="google" />
++          <option name="codename" value="lynx" />
++          <option name="id" value="lynx" />
++          <option name="labId" value="google" />
++          <option name="manufacturer" value="Google" />
++          <option name="name" value="Pixel 7a" />
++          <option name="screenDensity" value="420" />
++          <option name="screenX" value="1080" />
++          <option name="screenY" value="2400" />
++        </PersistentDeviceSelectionData>
++        <PersistentDeviceSelectionData>
++          <option name="api" value="33" />
++          <option name="brand" value="motorola" />
++          <option name="codename" value="maui" />
++          <option name="id" value="maui" />
++          <option name="labId" value="google" />
++          <option name="manufacturer" value="Motorola" />
++          <option name="name" value="moto g play - 2023" />
++          <option name="screenDensity" value="280" />
++          <option name="screenX" value="720" />
++          <option name="screenY" value="1600" />
++        </PersistentDeviceSelectionData>
++        <PersistentDeviceSelectionData>
++          <option name="api" value="34" />
++          <option name="brand" value="samsung" />
++          <option name="codename" value="o1q" />
++          <option name="id" value="o1q" />
++          <option name="labId" value="google" />
++          <option name="manufacturer" value="Samsung" />
++          <option name="name" value="Galaxy S21" />
++          <option name="screenDensity" value="421" />
++          <option name="screenX" value="1080" />
++          <option name="screenY" value="2400" />
++        </PersistentDeviceSelectionData>
++        <PersistentDeviceSelectionData>
++          <option name="api" value="31" />
++          <option name="brand" value="google" />
++          <option name="codename" value="oriole" />
++          <option name="id" value="oriole" />
++          <option name="labId" value="google" />
++          <option name="manufacturer" value="Google" />
++          <option name="name" value="Pixel 6" />
++          <option name="screenDensity" value="420" />
++          <option name="screenX" value="1080" />
++          <option name="screenY" value="2400" />
++        </PersistentDeviceSelectionData>
++        <PersistentDeviceSelectionData>
++          <option name="api" value="33" />
++          <option name="brand" value="google" />
++          <option name="codename" value="panther" />
++          <option name="id" value="panther" />
++          <option name="labId" value="google" />
++          <option name="manufacturer" value="Google" />
++          <option name="name" value="Pixel 7" />
++          <option name="screenDensity" value="420" />
++          <option name="screenX" value="1080" />
++          <option name="screenY" value="2400" />
++        </PersistentDeviceSelectionData>
++        <PersistentDeviceSelectionData>
++          <option name="api" value="34" />
++          <option name="brand" value="samsung" />
++          <option name="codename" value="q5q" />
++          <option name="id" value="q5q" />
++          <option name="labId" value="google" />
++          <option name="manufacturer" value="Samsung" />
++          <option name="name" value="Galaxy Z Fold5" />
++          <option name="screenDensity" value="420" />
++          <option name="screenX" value="1812" />
++          <option name="screenY" value="2176" />
++        </PersistentDeviceSelectionData>
++        <PersistentDeviceSelectionData>
++          <option name="api" value="34" />
++          <option name="brand" value="samsung" />
++          <option name="codename" value="q6q" />
++          <option name="id" value="q6q" />
++          <option name="labId" value="google" />
++          <option name="manufacturer" value="Samsung" />
++          <option name="name" value="Galaxy Z Fold6" />
++          <option name="screenDensity" value="420" />
++          <option name="screenX" value="1856" />
++          <option name="screenY" value="2160" />
++        </PersistentDeviceSelectionData>
++        <PersistentDeviceSelectionData>
++          <option name="api" value="30" />
++          <option name="brand" value="google" />
++          <option name="codename" value="r11" />
++          <option name="formFactor" value="Wear OS" />
++          <option name="id" value="r11" />
++          <option name="labId" value="google" />
++          <option name="manufacturer" value="Google" />
++          <option name="name" value="Pixel Watch" />
++          <option name="screenDensity" value="320" />
++          <option name="screenX" value="384" />
++          <option name="screenY" value="384" />
++          <option name="type" value="WEAR_OS" />
++        </PersistentDeviceSelectionData>
++        <PersistentDeviceSelectionData>
++          <option name="api" value="34" />
++          <option name="brand" value="samsung" />
++          <option name="codename" value="r11q" />
++          <option name="id" value="r11q" />
++          <option name="labId" value="google" />
++          <option name="manufacturer" value="Samsung" />
++          <option name="name" value="SM-S711U" />
++          <option name="screenDensity" value="450" />
++          <option name="screenX" value="1080" />
++          <option name="screenY" value="2340" />
++        </PersistentDeviceSelectionData>
++        <PersistentDeviceSelectionData>
++          <option name="api" value="30" />
++          <option name="brand" value="google" />
++          <option name="codename" value="redfin" />
++          <option name="id" value="redfin" />
++          <option name="labId" value="google" />
++          <option name="manufacturer" value="Google" />
++          <option name="name" value="Pixel 5" />
++          <option name="screenDensity" value="440" />
++          <option name="screenX" value="1080" />
++          <option name="screenY" value="2340" />
++        </PersistentDeviceSelectionData>
++        <PersistentDeviceSelectionData>
++          <option name="api" value="34" />
++          <option name="brand" value="google" />
++          <option name="codename" value="shiba" />
++          <option name="id" value="shiba" />
++          <option name="labId" value="google" />
++          <option name="manufacturer" value="Google" />
++          <option name="name" value="Pixel 8" />
++          <option name="screenDensity" value="420" />
++          <option name="screenX" value="1080" />
++          <option name="screenY" value="2400" />
++        </PersistentDeviceSelectionData>
++        <PersistentDeviceSelectionData>
++          <option name="api" value="34" />
++          <option name="brand" value="samsung" />
++          <option name="codename" value="t2q" />
++          <option name="id" value="t2q" />
++          <option name="labId" value="google" />
++          <option name="manufacturer" value="Samsung" />
++          <option name="name" value="Galaxy S21 Plus" />
++          <option name="screenDensity" value="394" />
++          <option name="screenX" value="1080" />
++          <option name="screenY" value="2400" />
++        </PersistentDeviceSelectionData>
++        <PersistentDeviceSelectionData>
++          <option name="api" value="33" />
++          <option name="brand" value="google" />
++          <option name="codename" value="tangorpro" />
++          <option name="formFactor" value="Tablet" />
++          <option name="id" value="tangorpro" />
++          <option name="labId" value="google" />
++          <option name="manufacturer" value="Google" />
++          <option name="name" value="Pixel Tablet" />
++          <option name="screenDensity" value="320" />
++          <option name="screenX" value="1600" />
++          <option name="screenY" value="2560" />
++        </PersistentDeviceSelectionData>
++        <PersistentDeviceSelectionData>
++          <option name="api" value="34" />
++          <option name="brand" value="google" />
++          <option name="codename" value="tokay" />
++          <option name="default" value="true" />
++          <option name="id" value="tokay" />
++          <option name="labId" value="google" />
++          <option name="manufacturer" value="Google" />
++          <option name="name" value="Pixel 9" />
++          <option name="screenDensity" value="420" />
++          <option name="screenX" value="1080" />
++          <option name="screenY" value="2424" />
++        </PersistentDeviceSelectionData>
++        <PersistentDeviceSelectionData>
++          <option name="api" value="35" />
++          <option name="brand" value="google" />
++          <option name="codename" value="tokay" />
++          <option name="default" value="true" />
++          <option name="id" value="tokay" />
++          <option name="labId" value="google" />
++          <option name="manufacturer" value="Google" />
++          <option name="name" value="Pixel 9" />
++          <option name="screenDensity" value="420" />
++          <option name="screenX" value="1080" />
++          <option name="screenY" value="2424" />
++        </PersistentDeviceSelectionData>
++      </list>
++    </option>
++  </component>
++</project>
+\ No newline at end of file
+diff --git a/node_modules/expo-notifications/android/.idea/gradle.xml b/node_modules/expo-notifications/android/.idea/gradle.xml
+new file mode 100644
+index 0000000..b838237
+--- /dev/null
++++ b/node_modules/expo-notifications/android/.idea/gradle.xml
+@@ -0,0 +1,12 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<project version="4">
++  <component name="GradleSettings">
++    <option name="linkedExternalProjectsSettings">
++      <GradleProjectSettings>
++        <option name="testRunner" value="CHOOSE_PER_TEST" />
++        <option name="externalProjectPath" value="$PROJECT_DIR$" />
++        <option name="gradleJvm" value="#GRADLE_LOCAL_JAVA_HOME" />
++      </GradleProjectSettings>
++    </option>
++  </component>
++</project>
+\ No newline at end of file
+diff --git a/node_modules/expo-notifications/android/.idea/migrations.xml b/node_modules/expo-notifications/android/.idea/migrations.xml
+new file mode 100644
+index 0000000..f8051a6
+--- /dev/null
++++ b/node_modules/expo-notifications/android/.idea/migrations.xml
+@@ -0,0 +1,10 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<project version="4">
++  <component name="ProjectMigrations">
++    <option name="MigrateToGradleLocalJavaHome">
++      <set>
++        <option value="$PROJECT_DIR$" />
++      </set>
++    </option>
++  </component>
++</project>
+\ No newline at end of file
+diff --git a/node_modules/expo-notifications/android/.idea/misc.xml b/node_modules/expo-notifications/android/.idea/misc.xml
+new file mode 100644
+index 0000000..3040d03
+--- /dev/null
++++ b/node_modules/expo-notifications/android/.idea/misc.xml
+@@ -0,0 +1,10 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<project version="4">
++  <component name="ExternalStorageConfigurationManager" enabled="true" />
++  <component name="ProjectRootManager">
++    <output url="file://$PROJECT_DIR$/build/classes" />
++  </component>
++  <component name="ProjectType">
++    <option name="id" value="Android" />
++  </component>
++</project>
+\ No newline at end of file
+diff --git a/node_modules/expo-notifications/android/.idea/runConfigurations.xml b/node_modules/expo-notifications/android/.idea/runConfigurations.xml
+new file mode 100644
+index 0000000..16660f1
+--- /dev/null
++++ b/node_modules/expo-notifications/android/.idea/runConfigurations.xml
+@@ -0,0 +1,17 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<project version="4">
++  <component name="RunConfigurationProducerService">
++    <option name="ignoredProducers">
++      <set>
++        <option value="com.intellij.execution.junit.AbstractAllInDirectoryConfigurationProducer" />
++        <option value="com.intellij.execution.junit.AllInPackageConfigurationProducer" />
++        <option value="com.intellij.execution.junit.PatternConfigurationProducer" />
++        <option value="com.intellij.execution.junit.TestInClassConfigurationProducer" />
++        <option value="com.intellij.execution.junit.UniqueIdConfigurationProducer" />
++        <option value="com.intellij.execution.junit.testDiscovery.JUnitTestDiscoveryConfigurationProducer" />
++        <option value="org.jetbrains.kotlin.idea.junit.KotlinJUnitRunConfigurationProducer" />
++        <option value="org.jetbrains.kotlin.idea.junit.KotlinPatternConfigurationProducer" />
++      </set>
++    </option>
++  </component>
++</project>
+\ No newline at end of file
+diff --git a/node_modules/expo-notifications/android/.idea/workspace.xml b/node_modules/expo-notifications/android/.idea/workspace.xml
+new file mode 100644
+index 0000000..df26928
+--- /dev/null
++++ b/node_modules/expo-notifications/android/.idea/workspace.xml
+@@ -0,0 +1,47 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<project version="4">
++  <component name="AutoImportSettings">
++    <option name="autoReloadType" value="NONE" />
++  </component>
++  <component name="ChangeListManager">
++    <list default="true" id="fed6a9c0-2e93-4b6e-953a-d1cd1e93b59f" name="Changes" comment="" />
++    <option name="SHOW_DIALOG" value="false" />
++    <option name="HIGHLIGHT_CONFLICTS" value="true" />
++    <option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
++    <option name="LAST_RESOLUTION" value="IGNORE" />
++  </component>
++  <component name="ClangdSettings">
++    <option name="formatViaClangd" value="false" />
++  </component>
++  <component name="ProjectColorInfo"><![CDATA[{
++  "associatedIndex": 4
++}]]></component>
++  <component name="ProjectId" id="2wCjuanPzVGKP91vdmftQVgUlaM" />
++  <component name="ProjectViewState">
++    <option name="hideEmptyMiddlePackages" value="true" />
++    <option name="showLibraryContents" value="true" />
++  </component>
++  <component name="PropertiesComponent"><![CDATA[{
++  "keyToString": {
++    "RunOnceActivity.ShowReadmeOnStart": "true",
++    "RunOnceActivity.cidr.known.project.marker": "true",
++    "RunOnceActivity.readMode.enableVisualFormatting": "true",
++    "android.gradle.sync.needed": "true",
++    "cf.first.check.clang-format": "false",
++    "cidr.known.project.marker": "true",
++    "kotlin-language-version-configured": "true",
++    "last_opened_file_path": "/Users/hailey/bsky/social-app/node_modules/expo-notifications/android"
++  }
++}]]></component>
++  <component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
++  <component name="TaskManager">
++    <task active="true" id="Default" summary="Default task">
++      <changelist id="fed6a9c0-2e93-4b6e-953a-d1cd1e93b59f" name="Changes" comment="" />
++      <created>1745552672693</created>
++      <option name="number" value="Default" />
++      <option name="presentableId" value="Default" />
++      <updated>1745552672693</updated>
++    </task>
++    <servers />
++  </component>
++</project>
+\ No newline at end of file
+diff --git a/node_modules/expo-notifications/android/build.gradle b/node_modules/expo-notifications/android/build.gradle
+index bc479ee..1ebfa00 100644
+--- a/node_modules/expo-notifications/android/build.gradle
++++ b/node_modules/expo-notifications/android/build.gradle
+@@ -42,6 +42,7 @@ dependencies {
+   implementation 'com.google.firebase:firebase-messaging:24.0.1'
+ 
+   implementation 'me.leolin:ShortcutBadger:1.1.22@aar'
++  implementation project(':expo-background-notification-handler')
+ 
+   if (project.findProject(':expo-modules-test-core')) {
+     testImplementation project(':expo-modules-test-core')
+diff --git a/node_modules/expo-notifications/android/local.properties b/node_modules/expo-notifications/android/local.properties
+new file mode 100644
+index 0000000..ab4c86d
+--- /dev/null
++++ b/node_modules/expo-notifications/android/local.properties
+@@ -0,0 +1,8 @@
++## This file must *NOT* be checked into Version Control Systems,
++# as it contains information specific to your local configuration.
++#
++# Location of the SDK. This is only used by Gradle.
++# For customization when using a Version Control System, please read the
++# header note.
++#Thu Apr 24 20:44:32 PDT 2025
++sdk.dir=/Users/hailey/Library/Android/sdk
+diff --git a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/interfaces/INotificationContent.kt b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/interfaces/INotificationContent.kt
+index 7b99e6c..45a450d 100644
+--- a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/interfaces/INotificationContent.kt
++++ b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/interfaces/INotificationContent.kt
+@@ -15,6 +15,7 @@ import org.json.JSONObject
+  * This interface exists to provide a common API for both classes.
+  * */
+ interface INotificationContent : Parcelable {
++  val channelId: String?
+   val title: String?
+   val text: String?
+   val subText: String?
+diff --git a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/NotificationContent.java b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/NotificationContent.java
+index 191b64e..fe8b3c5 100644
+--- a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/NotificationContent.java
++++ b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/NotificationContent.java
+@@ -35,6 +35,7 @@ import kotlin.coroutines.Continuation;
+  * Refactoring this class may require a migration strategy for the data stored in SharedPreferences.
+  */
+ public class NotificationContent implements Parcelable, Serializable, INotificationContent {
++  private String mChannelId;
+   private String mTitle;
+   private String mText;
+   private String mSubtitle;
+@@ -65,6 +66,11 @@ public class NotificationContent implements Parcelable, Serializable, INotificat
+     }
+   };
+ 
++  @Nullable
++  public String getChannelId() {
++    return mChannelId;
++  }
++
+   @Nullable
+   public String getTitle() {
+     return mTitle;
+@@ -158,6 +164,7 @@ public class NotificationContent implements Parcelable, Serializable, INotificat
+   }
+ 
+   protected NotificationContent(Parcel in) {
++    mChannelId = in.readString();
+     mTitle = in.readString();
+     mText = in.readString();
+     mSubtitle = in.readString();
+@@ -183,6 +190,7 @@ public class NotificationContent implements Parcelable, Serializable, INotificat
+ 
+   @Override
+   public void writeToParcel(Parcel dest, int flags) {
++    dest.writeString(mChannelId);
+     dest.writeString(mTitle);
+     dest.writeString(mText);
+     dest.writeString(mSubtitle);
+@@ -203,6 +211,7 @@ public class NotificationContent implements Parcelable, Serializable, INotificat
+   private static final long serialVersionUID = 397666843266836802L;
+ 
+   private void writeObject(java.io.ObjectOutputStream out) throws IOException {
++    out.writeObject(mChannelId);
+     out.writeObject(mTitle);
+     out.writeObject(mText);
+     out.writeObject(mSubtitle);
+@@ -285,6 +294,11 @@ public class NotificationContent implements Parcelable, Serializable, INotificat
+       useDefaultVibrationPattern();
+     }
+ 
++    public Builder setChannelId(String channelId) {
++      content.mChannelId = channelId;
++      return this;
++    }
++
+     public Builder setTitle(String title) {
+       content.mTitle = title;
+       return this;
+diff --git a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/NotificationData.kt b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/NotificationData.kt
+index 3af254c..3c77e9d 100644
+--- a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/NotificationData.kt
++++ b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/NotificationData.kt
+@@ -11,6 +11,9 @@ import org.json.JSONObject
+ * */
+ @JvmInline
+ value class NotificationData(private val data: Map<String, String>) {
++  val channelId: String?
++    get() = data["channelId"]
++
+   val title: String?
+     get() = data["title"]
+ 
+diff --git a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/RemoteNotificationContent.kt b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/RemoteNotificationContent.kt
+index d2cc6cf..6a48ff2 100644
+--- a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/RemoteNotificationContent.kt
++++ b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/RemoteNotificationContent.kt
+@@ -31,6 +31,8 @@ class RemoteNotificationContent(private val remoteMessage: RemoteMessage) : INot
+     return remoteMessage.notification?.imageUrl != null
+   }
+ 
++  override val channelId = remoteMessage.notification?.channelId ?: notificationData.channelId
++
+   override val title = remoteMessage.notification?.title ?: notificationData.title
+ 
+   override val text = remoteMessage.notification?.body ?: notificationData.message
+diff --git a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/presentation/builders/ExpoNotificationBuilder.kt b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/presentation/builders/ExpoNotificationBuilder.kt
+index 98f003f..2f745e8 100644
+--- a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/presentation/builders/ExpoNotificationBuilder.kt
++++ b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/presentation/builders/ExpoNotificationBuilder.kt
+@@ -101,6 +101,9 @@ open class ExpoNotificationBuilder(
+     builder.setOngoing(content.isSticky)
+ 
+     // see "Notification anatomy" https://developer.android.com/develop/ui/views/notifications#Templates
++    content.channelId?.let {
++      builder.setChannelId(it)
++    }
+     builder.setContentTitle(content.title)
+     builder.setContentText(content.text)
+     builder.setSubText(content.subText)
+diff --git a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/service/delegates/FirebaseMessagingDelegate.kt b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/service/delegates/FirebaseMessagingDelegate.kt
+index 90ca4ff..9d4cb09 100644
+--- a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/service/delegates/FirebaseMessagingDelegate.kt
++++ b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/service/delegates/FirebaseMessagingDelegate.kt
+@@ -3,6 +3,9 @@ package expo.modules.notifications.service.delegates
+ import android.content.Context
+ import android.os.Bundle
+ import com.google.firebase.messaging.RemoteMessage
++import expo.modules.backgroundnotificationhandler.BackgroundNotificationHandler
++import expo.modules.backgroundnotificationhandler.BackgroundNotificationHandlerInterface
++import expo.modules.backgroundnotificationhandler.ExpoBackgroundNotificationHandlerModule
+ import expo.modules.interfaces.taskManager.TaskServiceProviderHelper
+ import expo.modules.notifications.notifications.RemoteMessageSerializer
+ import expo.modules.notifications.notifications.background.BackgroundRemoteNotificationTaskConsumer
+@@ -18,7 +21,7 @@ import expo.modules.notifications.tokens.interfaces.FirebaseTokenListener
+ import java.lang.ref.WeakReference
+ import java.util.*
+ 
+-open class FirebaseMessagingDelegate(protected val context: Context) : FirebaseMessagingDelegate {
++open class FirebaseMessagingDelegate(protected val context: Context) : FirebaseMessagingDelegate, BackgroundNotificationHandlerInterface{
+   companion object {
+     // Unfortunately we cannot save state between instances of a service other way
+     // than by static properties. Fortunately, using weak references we can
+@@ -105,8 +108,19 @@ open class FirebaseMessagingDelegate(protected val context: Context) : FirebaseM
+     DebugLogging.logRemoteMessage("FirebaseMessagingDelegate.onMessageReceived: message", remoteMessage)
+     val notification = createNotification(remoteMessage)
+     DebugLogging.logNotification("FirebaseMessagingDelegate.onMessageReceived: notification", notification)
+-    NotificationsService.receive(context, notification)
+-    runTaskManagerTasks(context.applicationContext, RemoteMessageSerializer.toBundle(remoteMessage))
++    if (!ExpoBackgroundNotificationHandlerModule.isForegrounded) {
++      BackgroundNotificationHandler(context, this).handleMessage(remoteMessage)
++    } else {
++      NotificationsService.receive(context, notification)
++      runTaskManagerTasks(
++        context.applicationContext,
++        RemoteMessageSerializer.toBundle(remoteMessage)
++      )
++    }
++  }
++
++  override fun showMessage(remoteMessage: RemoteMessage) {
++    NotificationsService.receive(context, createNotification(remoteMessage))
+   }
+ 
+   protected fun createNotification(remoteMessage: RemoteMessage): Notification {
diff --git a/patches/expo-notifications+0.29.11.patch.md b/patches/expo-notifications+0.31.1.patch.md
index 05f841725..05f841725 100644
--- a/patches/expo-notifications+0.29.11.patch.md
+++ b/patches/expo-notifications+0.31.1.patch.md
diff --git a/patches/expo-updates+0.27.4.patch b/patches/expo-updates+0.28.12.patch
index 6fc4fc5fc..6fc4fc5fc 100644
--- a/patches/expo-updates+0.27.4.patch
+++ b/patches/expo-updates+0.28.12.patch
diff --git a/patches/expo-updates+0.26.10.patch.md b/patches/expo-updates+0.28.12.patch.md
index 6d5d7093d..6d5d7093d 100644
--- a/patches/expo-updates+0.26.10.patch.md
+++ b/patches/expo-updates+0.28.12.patch.md
diff --git a/patches/react-native+0.76.9.patch b/patches/react-native+0.76.9.patch
deleted file mode 100644
index 7e96d875c..000000000
--- a/patches/react-native+0.76.9.patch
+++ /dev/null
@@ -1,366 +0,0 @@
-diff --git a/node_modules/react-native/Libraries/StyleSheet/StyleSheetTypes.d.ts b/node_modules/react-native/Libraries/StyleSheet/StyleSheetTypes.d.ts
-index 62f52a7..ca30165 100644
---- a/node_modules/react-native/Libraries/StyleSheet/StyleSheetTypes.d.ts
-+++ b/node_modules/react-native/Libraries/StyleSheet/StyleSheetTypes.d.ts
-@@ -426,9 +426,10 @@ export interface ViewStyle extends FlexStyle, ShadowStyleIOS, TransformsStyle {
-    */
-   pointerEvents?: 'box-none' | 'none' | 'box-only' | 'auto' | undefined;
-   isolation?: 'auto' | 'isolate' | undefined;
--  cursor?: CursorValue | undefined;
-+  cursor?: CursorValue | string | undefined;
-   boxShadow?: ReadonlyArray<BoxShadowValue> | string | undefined;
-   filter?: ReadonlyArray<FilterFunction> | string | undefined;
-+  transformOrigin?: string | (string | number)[] | undefined;
- }
- 
- export type FontVariant =
-@@ -536,7 +537,11 @@ export interface TextStyle extends TextStyleIOS, TextStyleAndroid, ViewStyle {
-   textShadowOffset?: {width: number; height: number} | undefined;
-   textShadowRadius?: number | undefined;
-   textTransform?: 'none' | 'capitalize' | 'uppercase' | 'lowercase' | undefined;
--  userSelect?: 'auto' | 'none' | 'text' | 'contain' | 'all' | undefined;
-+  userSelect?: 'auto' | 'none' | 'text' | 'contain' | 'all' | string | undefined;
-+  cursor?: CursorValue | string | undefined;
-+  boxShadow?: ReadonlyArray<BoxShadowValue> | string | undefined;
-+  filter?: ReadonlyArray<FilterFunction> | string | undefined;
-+  transformOrigin?: string | (string | number)[] | undefined;
- }
- 
- /**
-@@ -558,5 +563,8 @@ export interface ImageStyle extends FlexStyle, ShadowStyleIOS, TransformsStyle {
-   tintColor?: ColorValue | undefined;
-   opacity?: AnimatableNumericValue | undefined;
-   objectFit?: 'cover' | 'contain' | 'fill' | 'scale-down' | undefined;
--  cursor?: CursorValue | undefined;
-+  cursor?: CursorValue | string | undefined;
-+  boxShadow?: ReadonlyArray<BoxShadowValue> | string | undefined;
-+  filter?: ReadonlyArray<FilterFunction> | string | undefined;
-+  transformOrigin?: string | (string | number)[] | undefined;
- }
-diff --git a/node_modules/react-native/React/Fabric/Mounting/ComponentViews/ScrollView/RCTEnhancedScrollView.mm b/node_modules/react-native/React/Fabric/Mounting/ComponentViews/ScrollView/RCTEnhancedScrollView.mm
-index 93af874..106f8ec 100644
---- a/node_modules/react-native/React/Fabric/Mounting/ComponentViews/ScrollView/RCTEnhancedScrollView.mm
-+++ b/node_modules/react-native/React/Fabric/Mounting/ComponentViews/ScrollView/RCTEnhancedScrollView.mm
-@@ -66,28 +66,51 @@
-  * ScrollView, we force it to be centered, but when you zoom or the content otherwise
-  * becomes larger than the ScrollView, there is no padding around the content but it
-  * can still fill the whole view.
-+ * This implementation is based on https://petersteinberger.com/blog/2013/how-to-center-uiscrollview/.
-  */
--- (void)setContentOffset:(CGPoint)contentOffset
-+-(void)centerContentIfNeeded
- {
--  if (_isSetContentOffsetDisabled) {
-+  if (!_centerContent) {
-     return;
-   }
- 
--  if (_centerContent && !CGSizeEqualToSize(self.contentSize, CGSizeZero)) {
--    CGSize scrollViewSize = self.bounds.size;
--    if (self.contentSize.width <= scrollViewSize.width) {
--      contentOffset.x = -(scrollViewSize.width - self.contentSize.width) / 2.0;
--    }
--    if (self.contentSize.height <= scrollViewSize.height) {
--      contentOffset.y = -(scrollViewSize.height - self.contentSize.height) / 2.0;
--    }
-+  CGSize contentSize = self.contentSize;
-+  CGSize boundsSize = self.bounds.size;
-+  if (CGSizeEqualToSize(contentSize, CGSizeZero) ||
-+      CGSizeEqualToSize(boundsSize, CGSizeZero)) {
-+    return;
-   }
- 
-+  CGFloat top = 0, left = 0;
-+  if (contentSize.width < boundsSize.width) {
-+    left = (boundsSize.width - contentSize.width) * 0.5f;
-+  }
-+  if (contentSize.height < boundsSize.height) {
-+    top = (boundsSize.height - contentSize.height) * 0.5f;
-+  }
-+  self.contentInset = UIEdgeInsetsMake(top, left, top, left);
-+}
-+
-+- (void)setContentOffset:(CGPoint)contentOffset
-+{
-+  if (_isSetContentOffsetDisabled) {
-+    return;
-+  }
-   super.contentOffset = CGPointMake(
-       RCTSanitizeNaNValue(contentOffset.x, @"scrollView.contentOffset.x"),
-       RCTSanitizeNaNValue(contentOffset.y, @"scrollView.contentOffset.y"));
- }
- 
-+- (void)setFrame:(CGRect)frame {
-+  [super setFrame:frame];
-+  [self centerContentIfNeeded];
-+}
-+
-+- (void)didAddSubview:(UIView *)subview {
-+  [super didAddSubview:subview];
-+  [self centerContentIfNeeded];
-+}
-+
- - (BOOL)touchesShouldCancelInContentView:(UIView *)view
- {
-   if ([_overridingDelegate respondsToSelector:@selector(touchesShouldCancelInContentView:)]) {
-@@ -257,6 +280,10 @@
-   }
- }
- 
-+- (void)scrollViewDidZoom:(__unused UIScrollView *)scrollView {
-+  [self centerContentIfNeeded];
-+}
-+
- #pragma mark -
- 
- - (BOOL)isHorizontal:(UIScrollView *)scrollView
-diff --git a/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.h b/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.h
-index e9b330f..ec5f58c 100644
---- a/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.h
-+++ b/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.h
-@@ -15,5 +15,8 @@
- @property (nonatomic, copy) NSString *title;
- @property (nonatomic, copy) RCTDirectEventBlock onRefresh;
- @property (nonatomic, weak) UIScrollView *scrollView;
-+@property (nonatomic, copy) UIColor *customTintColor;
-+
-+- (void)forwarderBeginRefreshing;
- 
- @end
-diff --git a/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.m b/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.m
-index 53bfd04..ff1b1ed 100644
---- a/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.m
-+++ b/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.m
-@@ -23,6 +23,7 @@
-   UIColor *_titleColor;
-   CGFloat _progressViewOffset;
-   BOOL _hasMovedToWindow;
-+  UIColor *_customTintColor;
- }
- 
- - (instancetype)init
-@@ -58,6 +59,12 @@ RCT_NOT_IMPLEMENTED(-(instancetype)initWithCoder : (NSCoder *)aDecoder)
-   _isInitialRender = false;
- }
- 
-+- (void)didMoveToSuperview
-+{
-+  [super didMoveToSuperview];
-+  [self setTintColor:_customTintColor];
-+}
-+
- - (void)didMoveToWindow
- {
-   [super didMoveToWindow];
-@@ -221,4 +228,50 @@ RCT_NOT_IMPLEMENTED(-(instancetype)initWithCoder : (NSCoder *)aDecoder)
-   }
- }
- 
-+// Fix for https://github.com/facebook/react-native/issues/43388
-+// A bug in iOS 17.4 causes the haptic to not play when refreshing if the tintColor
-+// is set before the refresh control gets added to the scrollview. We'll call this
-+// function whenever the superview changes. We'll also call it if the value of customTintColor
-+// changes.
-+- (void)setTintColor:(UIColor *)tintColor
-+{
-+  if ([self.superview isKindOfClass:[UIScrollView class]] && self.tintColor != tintColor) {
-+    [super setTintColor:tintColor];
-+  }
-+}
-+
-+// This method is used by Bluesky's ExpoScrollForwarder. This allows other React Native
-+// libraries to perform a refresh of a scrollview and access the refresh control's onRefresh
-+// function.
-+- (void)forwarderBeginRefreshing
-+{
-+  _refreshingProgrammatically = NO;
-+
-+  [self sizeToFit];
-+
-+  if (!self.scrollView) {
-+    return;
-+  }
-+
-+  UIScrollView *scrollView = (UIScrollView *)self.scrollView;
-+
-+  [UIView animateWithDuration:0.3
-+    delay:0
-+    options:UIViewAnimationOptionBeginFromCurrentState
-+    animations:^(void) {
-+      // Whenever we call this method, the scrollview will always be at a position of
-+      // -130 or less. Scrolling back to -65 simulates the default behavior of RCTRefreshControl
-+      [scrollView setContentOffset:CGPointMake(0, -65)];
-+    }
-+    completion:^(__unused BOOL finished) {
-+      [super beginRefreshing];
-+      [self setCurrentRefreshingState:super.refreshing];
-+
-+      if (self->_onRefresh) {
-+        self->_onRefresh(nil);
-+      }
-+    }
-+  ];
-+}
-+
- @end
-diff --git a/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControlManager.m b/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControlManager.m
-index 40aaf9c..1c60164 100644
---- a/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControlManager.m
-+++ b/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControlManager.m
-@@ -22,11 +22,12 @@ RCT_EXPORT_MODULE()
- 
- RCT_EXPORT_VIEW_PROPERTY(onRefresh, RCTDirectEventBlock)
- RCT_EXPORT_VIEW_PROPERTY(refreshing, BOOL)
--RCT_EXPORT_VIEW_PROPERTY(tintColor, UIColor)
- RCT_EXPORT_VIEW_PROPERTY(title, NSString)
- RCT_EXPORT_VIEW_PROPERTY(titleColor, UIColor)
- RCT_EXPORT_VIEW_PROPERTY(progressViewOffset, CGFloat)
- 
-+RCT_REMAP_VIEW_PROPERTY(tintColor, customTintColor, UIColor)
-+
- RCT_EXPORT_METHOD(setNativeRefreshing : (nonnull NSNumber *)viewTag toRefreshing : (BOOL)refreshing)
- {
-   [self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
-diff --git a/node_modules/react-native/React/Views/ScrollView/RCTScrollView.m b/node_modules/react-native/React/Views/ScrollView/RCTScrollView.m
-index 6f41b5c..9b4f77f 100644
---- a/node_modules/react-native/React/Views/ScrollView/RCTScrollView.m
-+++ b/node_modules/react-native/React/Views/ScrollView/RCTScrollView.m
-@@ -159,26 +159,8 @@
-   return !shouldDisableScrollInteraction;
- }
- 
--/*
-- * Automatically centers the content such that if the content is smaller than the
-- * ScrollView, we force it to be centered, but when you zoom or the content otherwise
-- * becomes larger than the ScrollView, there is no padding around the content but it
-- * can still fill the whole view.
-- */
- - (void)setContentOffset:(CGPoint)contentOffset
- {
--  UIView *contentView = [self contentView];
--  if (contentView && _centerContent && !CGSizeEqualToSize(contentView.frame.size, CGSizeZero)) {
--    CGSize subviewSize = contentView.frame.size;
--    CGSize scrollViewSize = self.bounds.size;
--    if (subviewSize.width <= scrollViewSize.width) {
--      contentOffset.x = -(scrollViewSize.width - subviewSize.width) / 2.0;
--    }
--    if (subviewSize.height <= scrollViewSize.height) {
--      contentOffset.y = -(scrollViewSize.height - subviewSize.height) / 2.0;
--    }
--  }
--
-   super.contentOffset = CGPointMake(
-       RCTSanitizeNaNValue(contentOffset.x, @"scrollView.contentOffset.x"),
-       RCTSanitizeNaNValue(contentOffset.y, @"scrollView.contentOffset.y"));
-@@ -433,6 +415,11 @@ static inline void RCTApplyTransformationAccordingLayoutDirection(
-   // Does nothing
- }
- 
-+- (void)setFrame:(CGRect)frame {
-+  [super setFrame:frame];
-+  [self centerContentIfNeeded];
-+}
-+
- - (void)insertReactSubview:(UIView *)view atIndex:(NSInteger)atIndex
- {
-   [super insertReactSubview:view atIndex:atIndex];
-@@ -449,6 +436,8 @@ static inline void RCTApplyTransformationAccordingLayoutDirection(
-     _contentView = view;
-     RCTApplyTransformationAccordingLayoutDirection(_contentView, self.reactLayoutDirection);
-     [_scrollView addSubview:view];
-+
-+    [self centerContentIfNeeded];
-   }
- }
- 
-@@ -658,9 +647,46 @@ static inline void RCTApplyTransformationAccordingLayoutDirection(
-   }
- 
- RCT_SCROLL_EVENT_HANDLER(scrollViewWillBeginDecelerating, onMomentumScrollBegin)
--RCT_SCROLL_EVENT_HANDLER(scrollViewDidZoom, onScroll)
- RCT_SCROLL_EVENT_HANDLER(scrollViewDidScrollToTop, onScrollToTop)
- 
-+-(void)scrollViewDidZoom : (UIScrollView *)scrollView
-+{
-+  [self centerContentIfNeeded];
-+
-+  RCT_SEND_SCROLL_EVENT(onScroll, nil);
-+  RCT_FORWARD_SCROLL_EVENT(scrollViewDidZoom : scrollView);
-+}
-+
-+/*
-+ * Automatically centers the content such that if the content is smaller than the
-+ * ScrollView, we force it to be centered, but when you zoom or the content otherwise
-+ * becomes larger than the ScrollView, there is no padding around the content but it
-+ * can still fill the whole view.
-+ * This implementation is based on https://petersteinberger.com/blog/2013/how-to-center-uiscrollview/.
-+ */
-+-(void)centerContentIfNeeded
-+{
-+  if (!_scrollView.centerContent) {
-+    return;
-+  }
-+
-+  CGSize contentSize = self.contentSize;
-+  CGSize boundsSize = self.bounds.size;
-+  if (CGSizeEqualToSize(contentSize, CGSizeZero) ||
-+      CGSizeEqualToSize(boundsSize, CGSizeZero)) {
-+    return;
-+  }
-+
-+  CGFloat top = 0, left = 0;
-+  if (contentSize.width < boundsSize.width) {
-+    left = (boundsSize.width - contentSize.width) * 0.5f;
-+  }
-+  if (contentSize.height < boundsSize.height) {
-+    top = (boundsSize.height - contentSize.height) * 0.5f;
-+  }
-+  _scrollView.contentInset = UIEdgeInsetsMake(top, left, top, left);
-+}
-+
- - (void)addScrollListener:(NSObject<UIScrollViewDelegate> *)scrollListener
- {
-   [_scrollListeners addObject:scrollListener];
-@@ -939,6 +965,7 @@ RCT_SCROLL_EVENT_HANDLER(scrollViewDidScrollToTop, onScrollToTop)
-   CGSize contentSize = self.contentSize;
-   if (!CGSizeEqualToSize(_scrollView.contentSize, contentSize)) {
-     _scrollView.contentSize = contentSize;
-+    [self centerContentIfNeeded];
-   }
- }
- 
-@@ -1061,6 +1088,22 @@ RCT_SET_AND_PRESERVE_OFFSET(setShowsHorizontalScrollIndicator, showsHorizontalSc
- RCT_SET_AND_PRESERVE_OFFSET(setShowsVerticalScrollIndicator, showsVerticalScrollIndicator, BOOL)
- RCT_SET_AND_PRESERVE_OFFSET(setZoomScale, zoomScale, CGFloat);
- 
-+- (void)setScrollIndicatorInsets:(UIEdgeInsets)value
-+{
-+  [_scrollView setScrollIndicatorInsets:value];
-+}
-+
-+- (UIEdgeInsets)scrollIndicatorInsets
-+{
-+  UIEdgeInsets verticalScrollIndicatorInsets = [_scrollView verticalScrollIndicatorInsets];
-+  UIEdgeInsets horizontalScrollIndicatorInsets = [_scrollView horizontalScrollIndicatorInsets];
-+  return UIEdgeInsetsMake(
-+      verticalScrollIndicatorInsets.top,
-+      horizontalScrollIndicatorInsets.left,
-+      verticalScrollIndicatorInsets.bottom,
-+      horizontalScrollIndicatorInsets.right);
-+}
-+
- - (void)setAutomaticallyAdjustsScrollIndicatorInsets:(BOOL)automaticallyAdjusts API_AVAILABLE(ios(13.0))
- {
-   // `automaticallyAdjustsScrollIndicatorInsets` is available since iOS 13.
-diff --git a/node_modules/react-native/React/Views/ScrollView/RCTScrollViewManager.m b/node_modules/react-native/React/Views/ScrollView/RCTScrollViewManager.m
-index cd1e7eb..c1d0172 100644
---- a/node_modules/react-native/React/Views/ScrollView/RCTScrollViewManager.m
-+++ b/node_modules/react-native/React/Views/ScrollView/RCTScrollViewManager.m
-@@ -83,6 +83,7 @@ RCT_EXPORT_VIEW_PROPERTY(showsVerticalScrollIndicator, BOOL)
- RCT_EXPORT_VIEW_PROPERTY(scrollEventThrottle, NSTimeInterval)
- RCT_EXPORT_VIEW_PROPERTY(zoomScale, CGFloat)
- RCT_EXPORT_VIEW_PROPERTY(contentInset, UIEdgeInsets)
-+RCT_EXPORT_VIEW_PROPERTY(scrollIndicatorInsets, UIEdgeInsets)
- RCT_EXPORT_VIEW_PROPERTY(verticalScrollIndicatorInsets, UIEdgeInsets)
- RCT_EXPORT_VIEW_PROPERTY(scrollToOverflowEnabled, BOOL)
- RCT_EXPORT_VIEW_PROPERTY(snapToInterval, int)
diff --git a/patches/react-native+0.79.2.patch b/patches/react-native+0.79.2.patch
new file mode 100644
index 000000000..609ae6617
--- /dev/null
+++ b/patches/react-native+0.79.2.patch
@@ -0,0 +1,119 @@
+diff --git a/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.h b/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.h
+index e9b330f..ec5f58c 100644
+--- a/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.h
++++ b/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.h
+@@ -15,5 +15,8 @@
+ @property (nonatomic, copy) NSString *title;
+ @property (nonatomic, copy) RCTDirectEventBlock onRefresh;
+ @property (nonatomic, weak) UIScrollView *scrollView;
++@property (nonatomic, copy) UIColor *customTintColor;
++
++- (void)forwarderBeginRefreshing;
+ 
+ @end
+diff --git a/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.m b/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.m
+index 53bfd04..ff1b1ed 100644
+--- a/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.m
++++ b/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.m
+@@ -23,6 +23,7 @@
+   UIColor *_titleColor;
+   CGFloat _progressViewOffset;
+   BOOL _hasMovedToWindow;
++  UIColor *_customTintColor;
+ }
+ 
+ - (instancetype)init
+@@ -58,6 +59,12 @@ RCT_NOT_IMPLEMENTED(-(instancetype)initWithCoder : (NSCoder *)aDecoder)
+   _isInitialRender = false;
+ }
+ 
++- (void)didMoveToSuperview
++{
++  [super didMoveToSuperview];
++  [self setTintColor:_customTintColor];
++}
++
+ - (void)didMoveToWindow
+ {
+   [super didMoveToWindow];
+@@ -221,4 +228,50 @@ RCT_NOT_IMPLEMENTED(-(instancetype)initWithCoder : (NSCoder *)aDecoder)
+   }
+ }
+ 
++// Fix for https://github.com/facebook/react-native/issues/43388
++// A bug in iOS 17.4 causes the haptic to not play when refreshing if the tintColor
++// is set before the refresh control gets added to the scrollview. We'll call this
++// function whenever the superview changes. We'll also call it if the value of customTintColor
++// changes.
++- (void)setTintColor:(UIColor *)tintColor
++{
++  if ([self.superview isKindOfClass:[UIScrollView class]] && self.tintColor != tintColor) {
++    [super setTintColor:tintColor];
++  }
++}
++
++// This method is used by Bluesky's ExpoScrollForwarder. This allows other React Native
++// libraries to perform a refresh of a scrollview and access the refresh control's onRefresh
++// function.
++- (void)forwarderBeginRefreshing
++{
++  _refreshingProgrammatically = NO;
++
++  [self sizeToFit];
++
++  if (!self.scrollView) {
++    return;
++  }
++
++  UIScrollView *scrollView = (UIScrollView *)self.scrollView;
++
++  [UIView animateWithDuration:0.3
++    delay:0
++    options:UIViewAnimationOptionBeginFromCurrentState
++    animations:^(void) {
++      // Whenever we call this method, the scrollview will always be at a position of
++      // -130 or less. Scrolling back to -65 simulates the default behavior of RCTRefreshControl
++      [scrollView setContentOffset:CGPointMake(0, -65)];
++    }
++    completion:^(__unused BOOL finished) {
++      [super beginRefreshing];
++      [self setCurrentRefreshingState:super.refreshing];
++
++      if (self->_onRefresh) {
++        self->_onRefresh(nil);
++      }
++    }
++  ];
++}
++
+ @end
+diff --git a/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControlManager.m b/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControlManager.m
+index 40aaf9c..1c60164 100644
+--- a/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControlManager.m
++++ b/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControlManager.m
+@@ -22,11 +22,12 @@ RCT_EXPORT_MODULE()
+ 
+ RCT_EXPORT_VIEW_PROPERTY(onRefresh, RCTDirectEventBlock)
+ RCT_EXPORT_VIEW_PROPERTY(refreshing, BOOL)
+-RCT_EXPORT_VIEW_PROPERTY(tintColor, UIColor)
+ RCT_EXPORT_VIEW_PROPERTY(title, NSString)
+ RCT_EXPORT_VIEW_PROPERTY(titleColor, UIColor)
+ RCT_EXPORT_VIEW_PROPERTY(progressViewOffset, CGFloat)
+ 
++RCT_REMAP_VIEW_PROPERTY(tintColor, customTintColor, UIColor)
++
+ RCT_EXPORT_METHOD(setNativeRefreshing : (nonnull NSNumber *)viewTag toRefreshing : (BOOL)refreshing)
+ {
+   [self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
+diff --git a/node_modules/react-native/React/Views/ScrollView/RCTScrollViewManager.m b/node_modules/react-native/React/Views/ScrollView/RCTScrollViewManager.m
+index cd1e7eb..c1d0172 100644
+--- a/node_modules/react-native/React/Views/ScrollView/RCTScrollViewManager.m
++++ b/node_modules/react-native/React/Views/ScrollView/RCTScrollViewManager.m
+@@ -83,6 +83,7 @@ RCT_EXPORT_VIEW_PROPERTY(showsVerticalScrollIndicator, BOOL)
+ RCT_EXPORT_VIEW_PROPERTY(scrollEventThrottle, NSTimeInterval)
+ RCT_EXPORT_VIEW_PROPERTY(zoomScale, CGFloat)
+ RCT_EXPORT_VIEW_PROPERTY(contentInset, UIEdgeInsets)
++RCT_EXPORT_VIEW_PROPERTY(scrollIndicatorInsets, UIEdgeInsets)
+ RCT_EXPORT_VIEW_PROPERTY(verticalScrollIndicatorInsets, UIEdgeInsets)
+ RCT_EXPORT_VIEW_PROPERTY(scrollToOverflowEnabled, BOOL)
+ RCT_EXPORT_VIEW_PROPERTY(snapToInterval, int)
diff --git a/patches/react-native+0.76.6.patch.md b/patches/react-native+0.79.2.patch.md
index eacb9f267..9c93aee5c 100644
--- a/patches/react-native+0.76.6.patch.md
+++ b/patches/react-native+0.79.2.patch.md
@@ -11,7 +11,3 @@ in the RN repo: https://github.com/facebook/react-native/issues/43388
 Patching `RCTRefreshControl.m` and `RCTRefreshControl.h` to add a new `forwarderBeginRefreshing` method to the class.
 This method is used by `ExpoScrollForwarder` to initiate a refresh of the underlying `UIScrollView` from inside that
 module.
-
-## ScrollView centerContent fix
-
-Includes https://github.com/facebook/react-native/pull/47591 early. Delete when it's in a release.
diff --git a/patches/react-native-gesture-handler+2.20.2.patch b/patches/react-native-gesture-handler+2.25.0.patch
index 431a9ab3e..431a9ab3e 100644
--- a/patches/react-native-gesture-handler+2.20.2.patch
+++ b/patches/react-native-gesture-handler+2.25.0.patch
diff --git a/patches/react-native-image-crop-picker+0.41.6.patch b/patches/react-native-image-crop-picker+0.42.0.patch
index 57589931a..c6124ad1e 100644
--- a/patches/react-native-image-crop-picker+0.41.6.patch
+++ b/patches/react-native-image-crop-picker+0.42.0.patch
@@ -1,5 +1,5 @@
 diff --git a/node_modules/react-native-image-crop-picker/android/src/main/AndroidManifest.xml b/node_modules/react-native-image-crop-picker/android/src/main/AndroidManifest.xml
-index 391f303..8e2c3db 100644
+index a08629b..fab6299 100644
 --- a/node_modules/react-native-image-crop-picker/android/src/main/AndroidManifest.xml
 +++ b/node_modules/react-native-image-crop-picker/android/src/main/AndroidManifest.xml
 @@ -24,7 +24,7 @@
@@ -8,12 +8,12 @@ index 391f303..8e2c3db 100644
              android:name="com.yalantis.ucrop.UCropActivity"
 -            android:theme="@style/Theme.AppCompat.Light.NoActionBar" />
 +            android:theme="@style/Theme.UCropNoEdgeToEdge" />
-     </application>
  
- </manifest>
+ 
+         <!-- Prompt Google Play services to install the backported photo picker module -->
 diff --git a/node_modules/react-native-image-crop-picker/android/src/main/res/values-v35/styles.xml b/node_modules/react-native-image-crop-picker/android/src/main/res/values-v35/styles.xml
 new file mode 100644
-index 0000000..396d5a8
+index 0000000..5301f74
 --- /dev/null
 +++ b/node_modules/react-native-image-crop-picker/android/src/main/res/values-v35/styles.xml
 @@ -0,0 +1,5 @@
@@ -22,26 +22,27 @@ index 0000000..396d5a8
 +        <item name="android:windowOptOutEdgeToEdgeEnforcement">true</item>
 +    </style>
 +</resources>
+\ No newline at end of file
 diff --git a/node_modules/react-native-image-crop-picker/android/src/main/res/values/styles.xml b/node_modules/react-native-image-crop-picker/android/src/main/res/values/styles.xml
 new file mode 100644
-index 0000000..50129b6
+index 0000000..55569aa
 --- /dev/null
 +++ b/node_modules/react-native-image-crop-picker/android/src/main/res/values/styles.xml
 @@ -0,0 +1,3 @@
 +<resources>
 +    <style name="Theme.UCropNoEdgeToEdge" parent="Theme.AppCompat.Light.NoActionBar"/>
 +</resources>
+\ No newline at end of file
 diff --git a/node_modules/react-native-image-crop-picker/ios/src/ImageCropPicker.m b/node_modules/react-native-image-crop-picker/ios/src/ImageCropPicker.m
-index 9f20973..68d4766 100644
+index 9f20973..c414a7a 100644
 --- a/node_modules/react-native-image-crop-picker/ios/src/ImageCropPicker.m
 +++ b/node_modules/react-native-image-crop-picker/ios/src/ImageCropPicker.m
-@@ -126,7 +126,8 @@ - (void) setConfiguration:(NSDictionary *)options
+@@ -126,7 +126,7 @@ - (void) setConfiguration:(NSDictionary *)options
  
  - (UIViewController*) getRootVC {
      UIViewController *root = [[[[UIApplication sharedApplication] delegate] window] rootViewController];
 -    while (root.presentedViewController != nil) {
-+    while (root.presentedViewController != nil &&
-+           !root.presentedViewController.isBeingDismissed) {
++    while (root.presentedViewController != nil && !root.presentedViewController.isBeingDismissed) {
          root = root.presentedViewController;
      }
      
diff --git a/patches/react-native-reanimated+3.17.5.patch b/patches/react-native-reanimated+3.17.5.patch
new file mode 100644
index 000000000..81cedee7e
--- /dev/null
+++ b/patches/react-native-reanimated+3.17.5.patch
@@ -0,0 +1,44 @@
+diff --git a/node_modules/react-native-reanimated/android/src/main/cpp/reanimated/android/NativeProxy.cpp b/node_modules/react-native-reanimated/android/src/main/cpp/reanimated/android/NativeProxy.cpp
+index eae3989..432745a 100644
+--- a/node_modules/react-native-reanimated/android/src/main/cpp/reanimated/android/NativeProxy.cpp
++++ b/node_modules/react-native-reanimated/android/src/main/cpp/reanimated/android/NativeProxy.cpp
+@@ -416,6 +416,10 @@ void NativeProxy::progressLayoutAnimation(
+       tag, newPropsJNI, isSharedTransition);
+ }
+ 
++void NativeProxy::endLayoutAnimation(int tag, bool shouldRemove) {
++  layoutAnimations_->cthis()->endLayoutAnimation(tag, shouldRemove);
++}
++
+ PlatformDepMethodsHolder NativeProxy::getPlatformDependentMethods() {
+ #ifdef RCT_NEW_ARCH_ENABLED
+   // nothing
+@@ -455,14 +459,7 @@ PlatformDepMethodsHolder NativeProxy::getPlatformDependentMethods() {
+   auto progressLayoutAnimation =
+       bindThis(&NativeProxy::progressLayoutAnimation);
+ 
+-  auto endLayoutAnimation = [weakThis = weak_from_this()](
+-                                int tag, bool removeView) {
+-    auto strongThis = weakThis.lock();
+-    if (!strongThis) {
+-      return;
+-    }
+-    strongThis->layoutAnimations_->cthis()->endLayoutAnimation(tag, removeView);
+-  };
++  auto endLayoutAnimation = bindThis(&NativeProxy::endLayoutAnimation);
+ 
+   auto maybeFlushUiUpdatesQueueFunction =
+       bindThis(&NativeProxy::maybeFlushUIUpdatesQueue);
+diff --git a/node_modules/react-native-reanimated/android/src/main/cpp/reanimated/android/NativeProxy.h b/node_modules/react-native-reanimated/android/src/main/cpp/reanimated/android/NativeProxy.h
+index 2ee2cc8..2edb5c9 100644
+--- a/node_modules/react-native-reanimated/android/src/main/cpp/reanimated/android/NativeProxy.h
++++ b/node_modules/react-native-reanimated/android/src/main/cpp/reanimated/android/NativeProxy.h
+@@ -234,6 +234,8 @@ class NativeProxy : public jni::HybridClass<NativeProxy>,
+       const jsi::Object &newProps,
+       bool isSharedTransition);
+ 
++  void endLayoutAnimation(int tag, bool shouldRemove);
++
+   /***
+    * Wraps a method of `NativeProxy` in a function object capturing `this`
+    * @tparam TReturn return type of passed method
diff --git a/patches/react-native-svg+15.8.0.patch b/patches/react-native-svg+15.11.2.patch
index 54540023f..54540023f 100644
--- a/patches/react-native-svg+15.8.0.patch
+++ b/patches/react-native-svg+15.11.2.patch