feat(MM-65147): upgrade to react-native 0.77.3 (#9253)

* feat(MM-65147): upgrade to react-native 0.77.3
* basic iOS & Android changes
* patch packages
* react-native-network-client temporary until fix upstream
* local updates
* delete patch for react-native-network-client
* update react-native-network-client@1.9.0
* update RNN patch package to fix kotlin bug
* revert unneeded changes
* changes based on PR review
* ensure insert not happening if any of the values are null
* update watermelondb to 2.81.0
* update watermelon patch file name
* update secure-pdf-viewer to use latest lib
* fix typescript errors
* update podfile.lock
* update podfile.lock
* update podfile.lock again?
* podfile.lock update again
* temporarily update hermes engine
* temp
* fix alamo issue.
* revert changes to pod update
* pod update vs pod install
* remove cache for a bit
* revert the pod caching
* oops
* update podfile.lock again
* fix(MM-66825): dynamic patching of 16kb pagesize (#9361)
* fix(MM-66825): dynamic patching of 16kb pagesize
* fix lint and tsc errors
* add npx patch-package
* run patcing somewhere else instead, but this will break  iOS
* move reinstall around
* simplify script
* expo-image wasn't updating
* update caching restore key
* using git apply
* fix lint issues
* readme changes
* remove some wrong instructions
* remove redundant npx patch-package
* update build script
This commit is contained in:
Rahim Rahman 2025-12-22 07:35:38 -07:00 committed by GitHub
parent 3a4e7b6cd6
commit 522812e126
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
29 changed files with 2311 additions and 1630 deletions

View file

@ -12,6 +12,13 @@ runs:
- name: ci/prepare-mobile-build
uses: ./.github/actions/prepare-mobile-build
- name: ci/apply-16kb-pagesize-patch
shell: bash
run: |
echo "::group::Apply 16KB page size compatibility patch"
npm run apply-16kb-pagesize-patch
echo "::endgroup::"
- name: ci/setup-java
uses: actions/setup-java@v4
with:

View file

@ -45,10 +45,9 @@ runs:
path: |
ios/Pods
libraries/@mattermost/intune/ios/Frameworks
key: ${{ runner.os }}-pods-v3-intune-${{ inputs.intune-enabled }}-${{ steps.intune-hash.outputs.hash }}-${{ hashFiles('ios/Podfile.lock') }}
key: ${{ runner.os }}-pods-v4-intune-${{ inputs.intune-enabled }}-${{ steps.intune-hash.outputs.hash }}-${{ hashFiles('ios/Podfile.lock') }}-${{ github.ref_name }}
restore-keys: |
${{ runner.os }}-pods-v3-intune-${{ inputs.intune-enabled }}-${{ steps.intune-hash.outputs.hash }}-
${{ runner.os }}-pods-v3-intune-${{ inputs.intune-enabled }}-
${{ runner.os }}-pods-v4-intune-${{ inputs.intune-enabled }}-${{ steps.intune-hash.outputs.hash }}-${{ hashFiles('ios/Podfile.lock') }}-
- name: ci/install-pods-dependencies
shell: bash

View file

@ -12,6 +12,34 @@ We plan on releasing monthly updates with new features - check the [changelog](h
**Important:** If you self-compile the Mattermost Mobile apps you also need to deploy your own [Mattermost Push Notification Service](https://github.com/mattermost/mattermost-push-proxy/releases).
# Android 16KB Page Size Support
**Temporary Requirement:** To comply with Google Play's 16KB page size requirement for Android devices, this project includes a compatibility patch that must be applied before building for Android.
### When to Apply the Patch
- **CI/CD Builds:** The patch is automatically applied in GitHub Actions for Android builds
- **Local Development:** If you're building Android locally and encounter 16KB page size related issues, run:
```bash
npm run apply-16kb-pagesize-patch
```
This script will:
1. Update package dependencies to compatible versions
2. Apply necessary code changes for 16KB page size support
3. Update patch files for modified dependencies
4. Regenerate `package-lock.json`
### ⚠️ Important Warnings
- **DO NOT commit the changes** applied by this patch to the repository
- **These changes will break iOS builds** if committed
- The patch is designed to be applied only during Android CI builds
- For local development, revert all changes after building Android
**Note:** This is a temporary solution until all dependencies natively support 16KB page sizes.
# How to Contribute
### Testing

View file

@ -135,7 +135,7 @@ class PushNotificationDataRunnable {
threadsArray.add(thread)
}
for(i in 0 until it.size()) {
val thread = it.getMap(i)
it.getMap(i)?.let { thread ->
val threadId = thread.getString("id")
if (threadId != null) {
if (threadIds.contains(threadId)) {
@ -153,6 +153,7 @@ class PushNotificationDataRunnable {
}
}
}
}
return threadsArray
}

View file

@ -54,23 +54,26 @@ fun insertCategoriesWithChannels(db: WMDatabase, orderCategories: ReadableMap) {
val categories = orderCategories.getArray("categories") ?: return
for (i in 0 until categories.size()) {
val category = categories.getMap(i)
val id = category.getString("id")
val teamId = category.getString("team_id")
val channelIds = category.getArray("channel_ids")
insertCategory(db, category)
category?.let { cat ->
val id = cat.getString("id")
val teamId = cat.getString("team_id")
val channelIds = cat.getArray("channel_ids")
insertCategory(db, cat)
if (id != null && teamId != null) {
channelIds?.let { insertCategoryChannels(db, id, teamId, it) }
}
}
}
}
fun insertChannelToDefaultCategory(db: WMDatabase, categoryChannels: ReadableArray) {
try {
for (i in 0 until categoryChannels.size()) {
val cc = categoryChannels.getMap(i)
categoryChannels.getMap(i)?.let { cc ->
val id = cc.getString("id")
val categoryId = cc.getString("category_id")
val channelId = cc.getString("channel_id")
if (id != null && categoryId != null && channelId != null) {
val count = countByColumn(db, "CategoryChannel", "category_id", categoryId)
db.execute(
"""
@ -81,6 +84,8 @@ fun insertChannelToDefaultCategory(db: WMDatabase, categoryChannels: ReadableArr
arrayOf(id, categoryId, channelId, if (count > 0) count + 1 else count)
)
}
}
}
} catch (e: Exception) {
e.printStackTrace()
}

View file

@ -26,7 +26,7 @@ internal fun DatabaseHelper.saveToDatabase(db: WMDatabase, data: ReadableMap, te
data.getArray("threads")?.let {
val threadsArray = ArrayList<ReadableMap>()
for (i in 0 until it.size()) {
threadsArray.add(it.getMap(i))
it.getMap(i)?.let { map -> threadsArray.add(map) }
}
handleThreads(db, threadsArray, teamId)
}

View file

@ -10,8 +10,10 @@ import com.nozbe.watermelondb.WMDatabase
internal fun findPostInChannel(chunks: ReadableArray, earliest: Double, latest: Double): ReadableMap? {
for (i in 0 until chunks.size()) {
val chunk = chunks.getMap(i)
if (earliest >= chunk.getDouble("earliest") || latest <= chunk.getDouble("latest")) {
return chunk
chunk?.let {
if (earliest >= it.getDouble("earliest") || latest <= it.getDouble("latest")) {
return it
}
}
}
@ -45,10 +47,12 @@ internal fun mergePostsInChannel(db: WMDatabase, existingChunks: ReadableArray,
for (i in 0 until existingChunks.size()) {
try {
val chunk = existingChunks.getMap(i)
if (newChunk.getDouble("earliest") <= chunk.getDouble("earliest") &&
newChunk.getDouble("latest") >= chunk.getDouble("latest")) {
db.execute("DELETE FROM PostsInChannel WHERE id = ?", arrayOf(chunk.getString("id")))
break
chunk?.let {
if (newChunk.getDouble("earliest") <= it.getDouble("earliest") &&
newChunk.getDouble("latest") >= it.getDouble("latest")) {
db.execute("DELETE FROM PostsInChannel WHERE id = ?", arrayOf(it.getString("id")))
return
}
}
} catch (e: Exception) {
e.printStackTrace()

View file

@ -83,6 +83,7 @@ internal fun insertThreadParticipants(db: WMDatabase, threadId: String, particip
for (i in 0 until participants.size()) {
try {
val participant = participants.getMap(i)
participant?.let {
val id = RandomId.generate()
db.execute(
"""
@ -90,8 +91,9 @@ internal fun insertThreadParticipants(db: WMDatabase, threadId: String, particip
(id, thread_id, user_id, _changed, _status)
VALUES (?, ?, ?, '', 'created')
""".trimIndent(),
arrayOf(id, threadId, participant.getString("id"))
arrayOf(id, threadId, it.getString("id"))
)
}
} catch (e: Exception) {
e.printStackTrace()
}

View file

@ -48,14 +48,15 @@ fun getCurrentUserLocale(db: WMDatabase): String {
fun handleUsers(db: WMDatabase, users: ReadableArray) {
for (i in 0 until users.size()) {
val user = users.getMap(i)
val roles = user.getString("roles") ?: ""
user?.let { u ->
val roles = u.getString("roles") ?: ""
val isBot = try {
user.getBoolean("is_bot")
u.getBoolean("is_bot")
} catch (e: NoSuchKeyException) {
false
}
val lastPictureUpdate = try { user.getDouble("last_picture_update") } catch (e: NoSuchKeyException) { 0 }
val lastPictureUpdate = try { u.getDouble("last_picture_update") } catch (e: NoSuchKeyException) { 0 }
try {
db.execute(
@ -66,15 +67,15 @@ fun handleUsers(db: WMDatabase, users: ReadableArray) {
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, '', 'created')
""".trimIndent(),
arrayOf(
user.getString("id"),
user.getString("auth_service"), user.getDouble("update_at"), user.getDouble("delete_at"),
user.getString("email"), user.getString("first_name"), isBot,
roles.contains("system_guest"), user.getString("last_name"), lastPictureUpdate,
user.getString("locale"), user.getString("nickname"), user.getString("position"),
roles, "", user.getString("username"), "{}",
ReadableMapUtils.toJSONObject(user.getMap("props")
u.getString("id"),
u.getString("auth_service"), u.getDouble("update_at"), u.getDouble("delete_at"),
u.getString("email"), u.getString("first_name"), isBot,
roles.contains("system_guest"), u.getString("last_name"), lastPictureUpdate,
u.getString("locale"), u.getString("nickname"), u.getString("position"),
roles, "", u.getString("username"), "{}",
ReadableMapUtils.toJSONObject(u.getMap("props")
?: Arguments.createMap()).toString(),
ReadableMapUtils.toJSONObject(user.getMap("timezone")
ReadableMapUtils.toJSONObject(u.getMap("timezone")
?: Arguments.createMap()).toString(),
)
)
@ -83,3 +84,4 @@ fun handleUsers(db: WMDatabase, users: ReadableArray) {
}
}
}
}

View file

@ -26,13 +26,15 @@ suspend fun PushNotificationDataRunnable.Companion.fetchMyChannel(db: WMDatabase
"D" -> {
profilesArray = fetchProfileInChannel(db, serverUrl, channelId)
if ((profilesArray?.size() ?: 0) > 0) {
val displayName = displayUsername(profilesArray!!.getMap(0), displayNameSetting)
profilesArray?.getMap(0)?.let { profile ->
val displayName = displayUsername(profile, displayNameSetting)
val data = Arguments.createMap()
data.merge(channelData)
data.putString("display_name", displayName)
channelData = data
}
}
}
"G" -> {
profilesArray = fetchProfileInChannel(db, serverUrl, channelId)
if ((profilesArray?.size() ?: 0) > 0) {
@ -117,8 +119,10 @@ private suspend fun PushNotificationDataRunnable.Companion.fetchProfileInChannel
if (profilesArray != null) {
for (i in 0 until profilesArray.size()) {
val profile = profilesArray.getMap(i)
if (profile.getString("id") != currentUserId) {
result.pushMap(profile)
profile?.let {
if (it.getString("id") != currentUserId) {
result.pushMap(it)
}
}
}
}
@ -152,7 +156,9 @@ private fun PushNotificationDataRunnable.Companion.displayGroupMessageName(profi
val names = ArrayList<String>()
for (i in 0 until profilesArray.size()) {
val profile = profilesArray.getMap(i)
names.add(displayUsername(profile, displayNameSetting))
profile?.let {
names.add(displayUsername(it, displayNameSetting))
}
}
return names.sortedWith { s1, s2 ->

View file

@ -62,7 +62,7 @@ internal suspend fun PushNotificationDataRunnable.Companion.fetchPosts(
val userIdsAlreadyLoaded = mutableListOf<String>()
if (loadedProfiles != null) {
for (i in 0 until loadedProfiles.size()) {
loadedProfiles.getMap(i).getString("id")?.let { userIdsAlreadyLoaded.add(it) }
loadedProfiles.getMap(i)?.getString("id")?.let { userIdsAlreadyLoaded.add(it) }
}
}
@ -95,12 +95,14 @@ internal suspend fun PushNotificationDataRunnable.Companion.fetchPosts(
if (attachments != null) {
for (i in 0 until attachments.size()) {
val attachment = attachments.getMap(i)
val pretext = attachment.getString("pretext")
val text = attachment.getString("text")
attachment?.let {
val pretext = it.getString("pretext")
val text = it.getString("text")
findNeededUsernames(pretext)
findNeededUsernames(text)
}
}
}
if (isCRTEnabled) {
@ -132,19 +134,19 @@ internal suspend fun PushNotificationDataRunnable.Companion.fetchPosts(
participants?.let {
for (i in 0 until it.size()) {
val participant = it.getMap(i)
val participantId = participant.getString("id")
participant?.let { p ->
val participantId = p.getString("id")
if (participantId != currentUserId && participantId != null) {
if (!threadParticipantUserIds.contains(participantId) && !userIdsAlreadyLoaded.contains(participantId)) {
threadParticipantUserIds.add(participantId)
}
if (!threadParticipantUsers.containsKey(participantId)) {
threadParticipantUsers[participantId] = participant
threadParticipantUsers[participantId] = p
}
}
val username = participant.getString("username")
val username = p.getString("username")
if (username != null && username != currentUsername && !threadParticipantUsernames.contains(username)) {
threadParticipantUsernames.add(username)
}
@ -152,6 +154,7 @@ internal suspend fun PushNotificationDataRunnable.Companion.fetchPosts(
}
}
}
}
val existingUserIds = queryIds(db, "User", userIds.toTypedArray())
val existingUsernames = queryByColumn(db, "User", "username", usernames.toTypedArray())

View file

@ -56,6 +56,6 @@ internal suspend fun PushNotificationDataRunnable.Companion.fetchNeededUsers(ser
internal fun PushNotificationDataRunnable.Companion.addUsersToList(users: ReadableArray, list: ArrayList<Any>) {
for (i in 0 until users.size()) {
list.add(users.getMap(i))
users.getMap(i)?.let { list.add(it) }
}
}

View file

@ -5,11 +5,11 @@ buildscript {
compileSdkVersion = 35
targetSdkVersion = 35
supportLibVersion = "35.0.0"
kotlinVersion = "1.9.25"
kotlinVersion = "2.0.21"
kotlin_version = kotlinVersion
RNNKotlinVersion = kotlinVersion
firebaseVersion = "24.1.0"
ndkVersion = "26.1.10909125"
ndkVersion = "27.1.12297006"
}
repositories {
mavenCentral()

View file

@ -1,49 +1,50 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
androidx.databinding:databinding-common:8.6.0=classpath
androidx.databinding:databinding-compiler-common:8.6.0=classpath
com.android.databinding:baseLibrary:8.6.0=classpath
com.android.tools.analytics-library:crash:31.6.0=classpath
com.android.tools.analytics-library:protos:31.6.0=classpath
com.android.tools.analytics-library:shared:31.6.0=classpath
com.android.tools.analytics-library:tracker:31.6.0=classpath
androidx.databinding:databinding-common:8.7.2=classpath
androidx.databinding:databinding-compiler-common:8.7.2=classpath
com.android.databinding:baseLibrary:8.7.2=classpath
com.android.tools.analytics-library:crash:31.7.2=classpath
com.android.tools.analytics-library:protos:31.7.2=classpath
com.android.tools.analytics-library:shared:31.7.2=classpath
com.android.tools.analytics-library:tracker:31.7.2=classpath
com.android.tools.build.jetifier:jetifier-core:1.0.0-beta10=classpath
com.android.tools.build.jetifier:jetifier-processor:1.0.0-beta10=classpath
com.android.tools.build:aapt2-proto:8.6.0-11315950=classpath
com.android.tools.build:aaptcompiler:8.6.0=classpath
com.android.tools.build:apksig:8.6.0=classpath
com.android.tools.build:apkzlib:8.6.0=classpath
com.android.tools.build:builder-model:8.6.0=classpath
com.android.tools.build:builder-test-api:8.6.0=classpath
com.android.tools.build:builder:8.6.0=classpath
com.android.tools.build:bundletool:1.16.0=classpath
com.android.tools.build:gradle-api:8.6.0=classpath
com.android.tools.build:gradle-settings-api:8.6.0=classpath
com.android.tools.build:gradle:8.6.0=classpath
com.android.tools.build:manifest-merger:31.6.0=classpath
com.android.tools.build:aapt2-proto:8.7.2-12006047=classpath
com.android.tools.build:aaptcompiler:8.7.2=classpath
com.android.tools.build:apksig:8.7.2=classpath
com.android.tools.build:apkzlib:8.7.2=classpath
com.android.tools.build:builder-model:8.7.2=classpath
com.android.tools.build:builder-test-api:8.7.2=classpath
com.android.tools.build:builder:8.7.2=classpath
com.android.tools.build:bundletool:1.17.1=classpath
com.android.tools.build:gradle-api:8.7.2=classpath
com.android.tools.build:gradle-settings-api:8.7.2=classpath
com.android.tools.build:gradle:8.7.2=classpath
com.android.tools.build:manifest-merger:31.7.2=classpath
com.android.tools.build:transform-api:2.0.0-deprecated-use-gradle-api=classpath
com.android.tools.ddms:ddmlib:31.6.0=classpath
com.android.tools.layoutlib:layoutlib-api:31.6.0=classpath
com.android.tools.lint:lint-model:31.6.0=classpath
com.android.tools.lint:lint-typedef-remover:31.6.0=classpath
com.android.tools.utp:android-device-provider-ddmlib-proto:31.6.0=classpath
com.android.tools.utp:android-device-provider-gradle-proto:31.6.0=classpath
com.android.tools.utp:android-test-plugin-host-additional-test-output-proto:31.6.0=classpath
com.android.tools.utp:android-test-plugin-host-apk-installer-proto:31.6.0=classpath
com.android.tools.utp:android-test-plugin-host-coverage-proto:31.6.0=classpath
com.android.tools.utp:android-test-plugin-host-emulator-control-proto:31.6.0=classpath
com.android.tools.utp:android-test-plugin-host-logcat-proto:31.6.0=classpath
com.android.tools.utp:android-test-plugin-host-retention-proto:31.6.0=classpath
com.android.tools.utp:android-test-plugin-result-listener-gradle-proto:31.6.0=classpath
com.android.tools:annotations:31.6.0=classpath
com.android.tools:common:31.6.0=classpath
com.android.tools:dvlib:31.6.0=classpath
com.android.tools:repository:31.6.0=classpath
com.android.tools:sdk-common:31.6.0=classpath
com.android.tools:sdklib:31.6.0=classpath
com.android:signflinger:8.6.0=classpath
com.android:zipflinger:8.6.0=classpath
com.android.tools.ddms:ddmlib:31.7.2=classpath
com.android.tools.layoutlib:layoutlib-api:31.7.2=classpath
com.android.tools.lint:lint-model:31.7.2=classpath
com.android.tools.lint:lint-typedef-remover:31.7.2=classpath
com.android.tools.utp:android-device-provider-ddmlib-proto:31.7.2=classpath
com.android.tools.utp:android-device-provider-gradle-proto:31.7.2=classpath
com.android.tools.utp:android-device-provider-profile-proto:31.7.2=classpath
com.android.tools.utp:android-test-plugin-host-additional-test-output-proto:31.7.2=classpath
com.android.tools.utp:android-test-plugin-host-apk-installer-proto:31.7.2=classpath
com.android.tools.utp:android-test-plugin-host-coverage-proto:31.7.2=classpath
com.android.tools.utp:android-test-plugin-host-emulator-control-proto:31.7.2=classpath
com.android.tools.utp:android-test-plugin-host-logcat-proto:31.7.2=classpath
com.android.tools.utp:android-test-plugin-host-retention-proto:31.7.2=classpath
com.android.tools.utp:android-test-plugin-result-listener-gradle-proto:31.7.2=classpath
com.android.tools:annotations:31.7.2=classpath
com.android.tools:common:31.7.2=classpath
com.android.tools:dvlib:31.7.2=classpath
com.android.tools:repository:31.7.2=classpath
com.android.tools:sdk-common:31.7.2=classpath
com.android.tools:sdklib:31.7.2=classpath
com.android:signflinger:8.7.2=classpath
com.android:zipflinger:8.7.2=classpath
com.google.android.gms:strict-version-matcher-plugin:1.2.4=classpath
com.google.android:annotations:4.1.1.4=classpath
com.google.api.grpc:proto-google-common-protos:2.17.0=classpath
@ -113,34 +114,29 @@ org.glassfish.jaxb:jaxb-runtime:2.3.2=classpath
org.glassfish.jaxb:txw2:2.3.2=classpath
org.jdom:jdom2:2.0.6=classpath
org.jetbrains.intellij.deps:trove4j:1.0.20200330=classpath
org.jetbrains.kotlin:kotlin-android-extensions:1.9.25=classpath
org.jetbrains.kotlin:kotlin-build-tools-api:1.9.25=classpath
org.jetbrains.kotlin:kotlin-compiler-embeddable:1.9.25=classpath
org.jetbrains.kotlin:kotlin-compiler-runner:1.9.25=classpath
org.jetbrains.kotlin:kotlin-daemon-client:1.9.25=classpath
org.jetbrains.kotlin:kotlin-daemon-embeddable:1.9.25=classpath
org.jetbrains.kotlin:kotlin-gradle-plugin-annotations:1.9.25=classpath
org.jetbrains.kotlin:kotlin-gradle-plugin-api:1.9.25=classpath
org.jetbrains.kotlin:kotlin-gradle-plugin-idea-proto:1.9.25=classpath
org.jetbrains.kotlin:kotlin-gradle-plugin-idea:1.9.25=classpath
org.jetbrains.kotlin:kotlin-gradle-plugin-model:1.9.25=classpath
org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.25=classpath
org.jetbrains.kotlin:kotlin-gradle-plugins-bom:1.9.25=classpath
org.jetbrains.kotlin:kotlin-klib-commonizer-api:1.9.25=classpath
org.jetbrains.kotlin:kotlin-native-utils:1.9.25=classpath
org.jetbrains.kotlin:kotlin-project-model:1.9.25=classpath
org.jetbrains.kotlin:kotlin-build-statistics:2.0.21=classpath
org.jetbrains.kotlin:kotlin-build-tools-api:2.0.21=classpath
org.jetbrains.kotlin:kotlin-compiler-embeddable:2.0.21=classpath
org.jetbrains.kotlin:kotlin-compiler-runner:2.0.21=classpath
org.jetbrains.kotlin:kotlin-daemon-client:2.0.21=classpath
org.jetbrains.kotlin:kotlin-daemon-embeddable:2.0.21=classpath
org.jetbrains.kotlin:kotlin-gradle-plugin-annotations:2.0.21=classpath
org.jetbrains.kotlin:kotlin-gradle-plugin-api:2.0.21=classpath
org.jetbrains.kotlin:kotlin-gradle-plugin-idea-proto:2.0.21=classpath
org.jetbrains.kotlin:kotlin-gradle-plugin-idea:2.0.21=classpath
org.jetbrains.kotlin:kotlin-gradle-plugin-model:2.0.21=classpath
org.jetbrains.kotlin:kotlin-gradle-plugin:2.0.21=classpath
org.jetbrains.kotlin:kotlin-gradle-plugins-bom:2.0.21=classpath
org.jetbrains.kotlin:kotlin-klib-commonizer-api:2.0.21=classpath
org.jetbrains.kotlin:kotlin-native-utils:2.0.21=classpath
org.jetbrains.kotlin:kotlin-reflect:1.9.20=classpath
org.jetbrains.kotlin:kotlin-scripting-common:1.9.25=classpath
org.jetbrains.kotlin:kotlin-scripting-compiler-embeddable:1.9.25=classpath
org.jetbrains.kotlin:kotlin-scripting-compiler-impl-embeddable:1.9.25=classpath
org.jetbrains.kotlin:kotlin-scripting-jvm:1.9.25=classpath
org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.9.20=classpath
org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.20=classpath
org.jetbrains.kotlin:kotlin-stdlib:1.9.25=classpath
org.jetbrains.kotlin:kotlin-tooling-core:1.9.25=classpath
org.jetbrains.kotlin:kotlin-util-io:1.9.25=classpath
org.jetbrains.kotlin:kotlin-util-klib:1.9.25=classpath
org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.5.0=classpath
org.jetbrains.kotlin:kotlin-stdlib:2.0.21=classpath
org.jetbrains.kotlin:kotlin-tooling-core:2.0.21=classpath
org.jetbrains.kotlin:kotlin-util-io:2.0.21=classpath
org.jetbrains.kotlin:kotlin-util-klib:2.0.21=classpath
org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.6.4=classpath
org.jetbrains:annotations:23.0.0=classpath
org.jvnet.staxex:stax-ex:1.8.1=classpath
org.ow2.asm:asm-analysis:9.6=classpath

View file

@ -79,9 +79,6 @@ function ScheduledPostIndicator({
);
return (
<View
className='ScheduledPostIndicator'
>
<View style={styles.container}>
<CompassIcon
color={changeOpacity(theme.centerChannelColor, 0.6)}
@ -105,7 +102,6 @@ function ScheduledPostIndicator({
</Text>
</Text>
</View>
</View>
);
}

View file

@ -12,12 +12,11 @@
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
1AC06461F0B9867B11829943 /* ExpoModulesProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24C9C33C1C823BB8E1B3E161 /* ExpoModulesProvider.swift */; };
266E7D53748BB8A1308B5CF2 /* libPods-MattermostShare.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B1BD2D4C53C3682D8892612F /* libPods-MattermostShare.a */; };
27C667A9295241B600E590D5 /* Sentry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27C667A8295241B600E590D5 /* Sentry.swift */; };
27C667AA295241B600E590D5 /* Sentry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27C667A8295241B600E590D5 /* Sentry.swift */; };
413A0FD06EA0DB2B3F30403F /* libPods-NotificationService.a in Frameworks */ = {isa = PBXBuildFile; fileRef = AEDDC97F55A1F6C056C6B1BC /* libPods-NotificationService.a */; };
536CC6C323E79287002C478C /* RNNotificationEventHandler+HandleReplyAction.m in Sources */ = {isa = PBXBuildFile; fileRef = 536CC6C123E79287002C478C /* RNNotificationEventHandler+HandleReplyAction.m */; };
58495E36BF1A4EAB93609E57 /* Metropolis-SemiBold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 54956DEFEBB74EF78C3A6AE5 /* Metropolis-SemiBold.ttf */; };
63A22C643F2AC11D1F536FFD /* Pods_NotificationService.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 482CD108BF5FC3AC64EB73F4 /* Pods_NotificationService.framework */; };
672D988829F1927F004228D6 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 672D984629F1927E004228D6 /* InfoPlist.strings */; };
672D988A29F1927F004228D6 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 672D984929F1927E004228D6 /* InfoPlist.strings */; };
672D988C29F1927F004228D6 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 672D984C29F1927E004228D6 /* InfoPlist.strings */; };
@ -170,11 +169,12 @@
83ABFD132C1C90D90029685B /* calls_cheerful.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = 83ABFD0F2C1C90D90029685B /* calls_cheerful.mp3 */; };
83ABFD142C1C90D90029685B /* calls_calm.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = 83ABFD102C1C90D90029685B /* calls_calm.mp3 */; };
83ABFD152C1C90D90029685B /* calls_urgent.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = 83ABFD112C1C90D90029685B /* calls_urgent.mp3 */; };
A8404C71A72745D3D79CF299 /* Pods_MattermostShare.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 46F51987161143CBA45CB13A /* Pods_MattermostShare.framework */; };
A94508A396424B2DB778AFE9 /* OpenSans-SemiBold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = E5C16B14E1CE4868886A1A00 /* OpenSans-SemiBold.ttf */; };
C84AE74C57DDE97D6C3D6924 /* libPods-Mattermost.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7A83BBA09DE89A630126EA06 /* libPods-Mattermost.a */; };
C9A107102BBD7C8700753CDC /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = C9A1070F2BBD7C8700753CDC /* PrivacyInfo.xcprivacy */; };
C9A107122BBDA00200753CDC /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = C9A107112BBDA00200753CDC /* PrivacyInfo.xcprivacy */; };
C9A107142BBDBC8F00753CDC /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = C9A107132BBDBC8F00753CDC /* PrivacyInfo.xcprivacy */; };
EC5A74C9C7BE208EB8ECA076 /* Pods_Mattermost.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1FA24657E0EE0B2378EFED0E /* Pods_Mattermost.framework */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@ -229,13 +229,16 @@
13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = Mattermost/Images.xcassets; sourceTree = "<group>"; };
13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = Mattermost/Info.plist; sourceTree = "<group>"; };
13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = Mattermost/main.m; sourceTree = "<group>"; };
1FA24657E0EE0B2378EFED0E /* Pods_Mattermost.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Mattermost.framework; sourceTree = BUILT_PRODUCTS_DIR; };
24C9C33C1C823BB8E1B3E161 /* ExpoModulesProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ExpoModulesProvider.swift; path = "Pods/Target Support Files/Pods-Mattermost/ExpoModulesProvider.swift"; sourceTree = "<group>"; };
27C667A8295241B600E590D5 /* Sentry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Sentry.swift; sourceTree = "<group>"; };
2E17B88EAD6181B9E9A24084 /* Pods-Mattermost.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Mattermost.debug.xcconfig"; path = "Target Support Files/Pods-Mattermost/Pods-Mattermost.debug.xcconfig"; sourceTree = "<group>"; };
32AC3D4EA79E44738A6E9766 /* OpenSans-BoldItalic.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "OpenSans-BoldItalic.ttf"; path = "../assets/fonts/OpenSans-BoldItalic.ttf"; sourceTree = "<group>"; };
3647DF63D6764CF093375861 /* OpenSans-ExtraBold.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "OpenSans-ExtraBold.ttf"; path = "../assets/fonts/OpenSans-ExtraBold.ttf"; sourceTree = "<group>"; };
41F3AFE83AAF4B74878AB78A /* OpenSans-Italic.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "OpenSans-Italic.ttf"; path = "../assets/fonts/OpenSans-Italic.ttf"; sourceTree = "<group>"; };
46F51987161143CBA45CB13A /* Pods_MattermostShare.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_MattermostShare.framework; sourceTree = BUILT_PRODUCTS_DIR; };
4751361789DCCAD0DBD95C16 /* Pods-MattermostShare.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MattermostShare.debug.xcconfig"; path = "Target Support Files/Pods-MattermostShare/Pods-MattermostShare.debug.xcconfig"; sourceTree = "<group>"; };
482CD108BF5FC3AC64EB73F4 /* Pods_NotificationService.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_NotificationService.framework; sourceTree = BUILT_PRODUCTS_DIR; };
495BC95F23565ABF00C40C83 /* libXCDYouTubeKit.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libXCDYouTubeKit.a; sourceTree = BUILT_PRODUCTS_DIR; };
495BC96123565ADD00C40C83 /* libYoutubePlayer-in-WKWebView.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = "libYoutubePlayer-in-WKWebView.a"; sourceTree = BUILT_PRODUCTS_DIR; };
499F7B3F235513F600E7AF6E /* libXCDYouTubeKit.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libXCDYouTubeKit.a; sourceTree = BUILT_PRODUCTS_DIR; };
@ -293,7 +296,6 @@
67FEAE272A1261A000DDF4AE /* ro */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ro; path = Localizable.strings; sourceTree = "<group>"; };
67FEAE2B2A127C3600DDF4AE /* NumberFormatter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NumberFormatter.swift; sourceTree = "<group>"; };
6BAF8296411D4657B5A0E8F8 /* libRNReactNativeDocViewer.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNReactNativeDocViewer.a; sourceTree = "<group>"; };
7A83BBA09DE89A630126EA06 /* libPods-Mattermost.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Mattermost.a"; sourceTree = BUILT_PRODUCTS_DIR; };
7F0F4B0924BA173900E14C60 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = SplashScreenResource/LaunchScreen.storyboard; sourceTree = "<group>"; };
7F151D3D221B062700FAD8F3 /* RuntimeUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RuntimeUtils.swift; sourceTree = "<group>"; };
7F151D43221B082A00FAD8F3 /* Mattermost-Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "Mattermost-Bridging-Header.h"; path = "Mattermost/Mattermost-Bridging-Header.h"; sourceTree = "<group>"; };
@ -377,8 +379,6 @@
83ABFD102C1C90D90029685B /* calls_calm.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; name = calls_calm.mp3; path = ../assets/sounds/calls_calm.mp3; sourceTree = "<group>"; };
83ABFD112C1C90D90029685B /* calls_urgent.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; name = calls_urgent.mp3; path = ../assets/sounds/calls_urgent.mp3; sourceTree = "<group>"; };
A10297DBBE728B2BF1BC045E /* Pods-NotificationService.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationService.debug.xcconfig"; path = "Target Support Files/Pods-NotificationService/Pods-NotificationService.debug.xcconfig"; sourceTree = "<group>"; };
AEDDC97F55A1F6C056C6B1BC /* libPods-NotificationService.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-NotificationService.a"; sourceTree = BUILT_PRODUCTS_DIR; };
B1BD2D4C53C3682D8892612F /* libPods-MattermostShare.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-MattermostShare.a"; sourceTree = BUILT_PRODUCTS_DIR; };
BC977883E2624E05975CA65B /* OpenSans-Regular.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "OpenSans-Regular.ttf"; path = "../assets/fonts/OpenSans-Regular.ttf"; sourceTree = "<group>"; };
BE17F630DB5D41FD93F32D22 /* OpenSans-LightItalic.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "OpenSans-LightItalic.ttf"; path = "../assets/fonts/OpenSans-LightItalic.ttf"; sourceTree = "<group>"; };
C7E622B6B1B605983E8E23B7 /* Pods-MattermostShare.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MattermostShare.release.xcconfig"; path = "Target Support Files/Pods-MattermostShare/Pods-MattermostShare.release.xcconfig"; sourceTree = "<group>"; };
@ -397,7 +397,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
C84AE74C57DDE97D6C3D6924 /* libPods-Mattermost.a in Frameworks */,
EC5A74C9C7BE208EB8ECA076 /* Pods_Mattermost.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -405,7 +405,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
413A0FD06EA0DB2B3F30403F /* libPods-NotificationService.a in Frameworks */,
63A22C643F2AC11D1F536FFD /* Pods_NotificationService.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -413,7 +413,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
266E7D53748BB8A1308B5CF2 /* libPods-MattermostShare.a in Frameworks */,
A8404C71A72745D3D79CF299 /* Pods_MattermostShare.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -562,9 +562,9 @@
7FFE32BF1FD9CCAA0038C7A0 /* Sentry.framework */,
7F43D6051F6BF9EB001FC614 /* libPods-Mattermost.a */,
81061F4CBB31484A94D5A8EE /* libz.tbd */,
7A83BBA09DE89A630126EA06 /* libPods-Mattermost.a */,
AEDDC97F55A1F6C056C6B1BC /* libPods-NotificationService.a */,
B1BD2D4C53C3682D8892612F /* libPods-MattermostShare.a */,
1FA24657E0EE0B2378EFED0E /* Pods_Mattermost.framework */,
46F51987161143CBA45CB13A /* Pods_MattermostShare.framework */,
482CD108BF5FC3AC64EB73F4 /* Pods_NotificationService.framework */,
);
name = Frameworks;
sourceTree = "<group>";
@ -1073,8 +1073,6 @@
7FC5698F28563FDB000B0905 /* PBXTargetDependency */,
);
name = Mattermost;
packageProductDependencies = (
);
productName = "Hello World";
productReference = 13B07F961A680F5B00A75B9A /* Mattermost.app */;
productType = "com.apple.product-type.application";
@ -1094,8 +1092,6 @@
dependencies = (
);
name = NotificationService;
packageProductDependencies = (
);
productName = NotificationService;
productReference = 7F581D32221ED5C60099E66B /* NotificationService.appex */;
productType = "com.apple.product-type.app-extension";
@ -1115,8 +1111,6 @@
dependencies = (
);
name = MattermostShare;
packageProductDependencies = (
);
productName = MattermostShare;
productReference = 7FC5698628563FDB000B0905 /* MattermostShare.appex */;
productType = "com.apple.product-type.app-extension";
@ -1198,8 +1192,6 @@
uk,
);
mainGroup = 83CBB9F61A601CBA00E9B192;
packageReferences = (
);
productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */;
projectDirPath = "";
projectRoot = "";
@ -2159,6 +2151,8 @@
isa = XCBuildConfiguration;
baseConfigurationReference = A10297DBBE728B2BF1BC045E /* Pods-NotificationService.debug.xcconfig */;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
APPLICATION_EXTENSION_API_ONLY = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "$(inherited)";
@ -2208,6 +2202,8 @@
isa = XCBuildConfiguration;
baseConfigurationReference = FF7D3AE3E5E892576497A111 /* Pods-NotificationService.release.xcconfig */;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
APPLICATION_EXTENSION_API_ONLY = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "$(inherited)";
@ -2254,6 +2250,8 @@
isa = XCBuildConfiguration;
baseConfigurationReference = 4751361789DCCAD0DBD95C16 /* Pods-MattermostShare.debug.xcconfig */;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
APPLICATION_EXTENSION_API_ONLY = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "$(inherited)";
@ -2304,6 +2302,8 @@
isa = XCBuildConfiguration;
baseConfigurationReference = C7E622B6B1B605983E8E23B7 /* Pods-MattermostShare.release.xcconfig */;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
APPLICATION_EXTENSION_API_ONLY = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "$(inherited)";
@ -2392,6 +2392,17 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
HEADER_SEARCH_PATHS = (
"$(inherited)",
"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon/ReactCommon.framework/Headers",
"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon/ReactCommon.framework/Headers/react/nativemodule/core",
"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon-Samples/ReactCommon_Samples.framework/Headers",
"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon-Samples/ReactCommon_Samples.framework/Headers/platform/ios",
"${PODS_CONFIGURATION_BUILD_DIR}/React-Fabric/React_Fabric.framework/Headers/react/renderer/components/view/platform/cxx",
"${PODS_CONFIGURATION_BUILD_DIR}/React-NativeModulesApple/React_NativeModulesApple.framework/Headers",
"${PODS_CONFIGURATION_BUILD_DIR}/React-graphics/React_graphics.framework/Headers",
"${PODS_CONFIGURATION_BUILD_DIR}/React-graphics/React_graphics.framework/Headers/react/renderer/graphics/platform/ios",
);
IPHONEOS_DEPLOYMENT_TARGET = 13.4;
LD = "";
LDPLUSPLUS = "";
@ -2455,7 +2466,16 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
HEADER_SEARCH_PATHS = "";
HEADER_SEARCH_PATHS = (
"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon/ReactCommon.framework/Headers",
"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon/ReactCommon.framework/Headers/react/nativemodule/core",
"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon-Samples/ReactCommon_Samples.framework/Headers",
"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon-Samples/ReactCommon_Samples.framework/Headers/platform/ios",
"${PODS_CONFIGURATION_BUILD_DIR}/React-Fabric/React_Fabric.framework/Headers/react/renderer/components/view/platform/cxx",
"${PODS_CONFIGURATION_BUILD_DIR}/React-NativeModulesApple/React_NativeModulesApple.framework/Headers",
"${PODS_CONFIGURATION_BUILD_DIR}/React-graphics/React_graphics.framework/Headers",
"${PODS_CONFIGURATION_BUILD_DIR}/React-graphics/React_graphics.framework/Headers/react/renderer/graphics/platform/ios",
);
IPHONEOS_DEPLOYMENT_TARGET = 13.4;
LD = "";
LDPLUSPLUS = "";

File diff suppressed because it is too large Load diff

View file

@ -18,10 +18,11 @@ class MattermostHardwareKeyboardPackage : TurboReactPackage() {
override fun getReactModuleInfoProvider() = ReactModuleInfoProvider {
mapOf(
MattermostHardwareKeyboardImpl.NAME to ReactModuleInfo(
MattermostHardwareKeyboardImpl.NAME,
MattermostHardwareKeyboardImpl.NAME,
_canOverrideExistingModule = false,
_needsEagerInit = false,
name = MattermostHardwareKeyboardImpl.NAME,
className = MattermostHardwareKeyboardImpl.NAME,
canOverrideExistingModule = false,
needsEagerInit = false,
hasConstants = false,
isCxxModule = false,
isTurboModule = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED
)

View file

@ -20,10 +20,11 @@ class MattermostSharePackage : TurboReactPackage() {
val moduleInfos: MutableMap<String, ReactModuleInfo> = HashMap()
val isTurboModule: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED
moduleInfos[MattermostShareImpl.NAME] = ReactModuleInfo(
MattermostShareImpl.NAME,
MattermostShareImpl.NAME,
_canOverrideExistingModule = false,
_needsEagerInit = false,
name = MattermostShareImpl.NAME,
className = MattermostShareImpl.NAME,
canOverrideExistingModule = false,
needsEagerInit = false,
hasConstants = false,
isCxxModule = false,
isTurboModule = isTurboModule
)

View file

@ -14,8 +14,8 @@ fun ReadableArray.toJson(): JSONArray {
ReadableType.Boolean -> jsonArray.put(this.getBoolean(i))
ReadableType.Number -> jsonArray.put(this.getDouble(i))
ReadableType.String -> jsonArray.put(this.getString(i))
ReadableType.Map -> jsonArray.put(this.getMap(i).toJson())
ReadableType.Array -> jsonArray.put(this.getArray(i).toJson())
ReadableType.Map -> this.getMap(i)?.toJson()?.let { jsonArray.put(it) }
ReadableType.Array -> this.getArray(i)?.toJson()?.let { jsonArray.put(it) }
}
}
return jsonArray

View file

@ -18,10 +18,11 @@ class RNUtilsPackage : TurboReactPackage() {
override fun getReactModuleInfoProvider() = ReactModuleInfoProvider {
mapOf(
RNUtilsModuleImpl.NAME to ReactModuleInfo(
RNUtilsModuleImpl.NAME,
RNUtilsModuleImpl.NAME,
_canOverrideExistingModule = false,
_needsEagerInit = false,
name = RNUtilsModuleImpl.NAME,
className = RNUtilsModuleImpl.NAME,
canOverrideExistingModule = false,
needsEagerInit = false,
hasConstants = false,
isCxxModule = false,
isTurboModule = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED
)

View file

@ -67,5 +67,5 @@ dependencies {
implementation 'com.facebook.react:react-native'
implementation 'androidx.security:security-crypto:1.0.0'
implementation "org.jetbrains.kotlin:kotlin-stdlib"
implementation 'com.github.mattermost:mattermost-android-pdfium:v1.0.1'
implementation 'com.github.mattermost:mattermost-android-pdfium:v1.1.0'
}

1510
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -30,7 +30,7 @@
"@mattermost/rnutils": "file:./libraries/@mattermost/rnutils",
"@mattermost/secure-pdf-viewer": "file:./libraries/@mattermost/secure-pdf-viewer",
"@msgpack/msgpack": "3.1.1",
"@nozbe/watermelondb": "0.28.0",
"@nozbe/watermelondb": "0.28.1-0",
"@react-native-camera-roll/camera-roll": "7.10.0",
"@react-native-clipboard/clipboard": "1.16.2",
"@react-native-community/cli": "15.1.3",
@ -53,7 +53,7 @@
"deep-equal": "2.2.3",
"deepmerge": "4.3.1",
"emoji-regex": "10.4.0",
"expo": "52.0.44",
"expo": "52.0.47",
"expo-application": "6.0.2",
"expo-crypto": "14.0.2",
"expo-device": "7.0.3",
@ -74,7 +74,7 @@
"react": "18.3.1",
"react-freeze": "1.0.4",
"react-intl": "7.1.10",
"react-native": "0.76.9",
"react-native": "0.77.3",
"react-native-background-timer": "2.4.1",
"react-native-document-picker": "9.3.1",
"react-native-dotenv": "3.4.11",
@ -121,10 +121,10 @@
"@babel/preset-typescript": "7.27.0",
"@babel/register": "7.25.9",
"@babel/runtime": "7.27.0",
"@react-native/babel-preset": "0.76.9",
"@react-native/eslint-config": "0.76.9",
"@react-native/metro-config": "0.76.9",
"@react-native/typescript-config": "0.76.9",
"@react-native/babel-preset": "0.77.3",
"@react-native/eslint-config": "0.77.3",
"@react-native/metro-config": "0.77.3",
"@react-native/typescript-config": "0.77.3",
"@stylistic/eslint-plugin-ts": "4.2.0",
"@testing-library/react-hooks": "8.0.1",
"@testing-library/react-native": "13.2.0",
@ -176,6 +176,7 @@
},
"scripts": {
"android": "react-native run-android",
"apply-16kb-pagesize-patch": "node ./scripts/android-16kb-pagesize/apply-patch.js ./scripts/android-16kb-pagesize/9325-full.diff --apply",
"build:android": "./scripts/build.sh apk",
"build:android-unsigned": "./scripts/build.sh apk unsigned",
"build:ios": "./scripts/build.sh ipa",
@ -227,10 +228,10 @@
"react-test-renderer": "^18.3.1"
},
"@react-native-community/datetimepicker": {
"react-native": "^0.76.5"
"react-native": "^0.77.3"
},
"react-native-windows": {
"react-native": "^0.76.5"
"react-native": "^0.77.3"
},
"@react-native/eslint-config@0.76.5": {
"@typescript-eslint/eslint-plugin": "^8.29.1"

View file

@ -383,18 +383,18 @@ index 551f72b..f275c18 100644
- override fun onInterceptTouchEvent(event: MotionEvent): Boolean {
- mJSTouchDispatcher.handleTouchEvent(event, getEventDispatcher())
+ override fun onInterceptTouchEvent(event: MotionEvent?): Boolean {
+ event?.let {
+ mJSTouchDispatcher.handleTouchEvent(it, getEventDispatcher()!!)
+ override fun onInterceptTouchEvent(event: MotionEvent): Boolean {
+ getEventDispatcher()?.let {
+ mJSTouchDispatcher.handleTouchEvent(event, it)
+ }
return super.onInterceptTouchEvent(event)
}
- override fun onTouchEvent(event: MotionEvent): Boolean {
- mJSTouchDispatcher.handleTouchEvent(event, getEventDispatcher())
+ override fun onTouchEvent(event: MotionEvent?): Boolean {
+ event?.let {
+ mJSTouchDispatcher.handleTouchEvent(it, getEventDispatcher()!!)
+ override fun onTouchEvent(event: MotionEvent): Boolean {
+ getEventDispatcher()?.let {
+ mJSTouchDispatcher.handleTouchEvent(event, it)
+ }
super.onTouchEvent(event)
return true

View file

@ -0,0 +1,392 @@
diff --git a/android/buildscript-gradle.lockfile b/android/buildscript-gradle.lockfile
index dfde0b3d60..3a4a440688 100644
--- a/android/buildscript-gradle.lockfile
+++ b/android/buildscript-gradle.lockfile
@@ -130,6 +130,7 @@ org.jetbrains.kotlin:kotlin-gradle-plugins-bom:2.0.21=classpath
org.jetbrains.kotlin:kotlin-klib-commonizer-api:2.0.21=classpath
org.jetbrains.kotlin:kotlin-native-utils:2.0.21=classpath
org.jetbrains.kotlin:kotlin-reflect:1.9.20=classpath
+org.jetbrains.kotlin:kotlin-stdlib-common:2.0.21=classpath
org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.9.20=classpath
org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.20=classpath
org.jetbrains.kotlin:kotlin-stdlib:2.0.21=classpath
@@ -137,6 +138,11 @@ org.jetbrains.kotlin:kotlin-tooling-core:2.0.21=classpath
org.jetbrains.kotlin:kotlin-util-io:2.0.21=classpath
org.jetbrains.kotlin:kotlin-util-klib:2.0.21=classpath
org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.6.4=classpath
+org.jetbrains.kotlinx:kotlinx-serialization-bom:1.6.3=classpath
+org.jetbrains.kotlinx:kotlinx-serialization-core-jvm:1.6.3=classpath
+org.jetbrains.kotlinx:kotlinx-serialization-core:1.6.3=classpath
+org.jetbrains.kotlinx:kotlinx-serialization-json-jvm:1.6.3=classpath
+org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3=classpath
org.jetbrains:annotations:23.0.0=classpath
org.jvnet.staxex:stax-ex:1.8.1=classpath
org.ow2.asm:asm-analysis:9.6=classpath
diff --git a/app.json b/app.json
index 08eb45fcd9..914911c17a 100644
--- a/app.json
+++ b/app.json
@@ -1,4 +1,7 @@
{
"name": "Mattermost",
- "displayName": "Mattermost"
+ "displayName": "Mattermost",
+ "plugins": [
+ "expo-web-browser"
+ ]
}
diff --git a/app/components/expo_image/index.tsx b/app/components/expo_image/index.tsx
index 9dbffd7ca6..bd70fffb9c 100644
--- a/app/components/expo_image/index.tsx
+++ b/app/components/expo_image/index.tsx
@@ -8,6 +8,8 @@ import Animated from 'react-native-reanimated';
import {useServerUrl} from '@context/server';
import {urlSafeBase64Encode} from '@utils/security';
+import type {SharedRefType} from 'expo';
+
type ExpoImagePropsWithId = ImageProps & {id: string};
type ExpoImagePropsMemoryOnly = ImageProps & {cachePolicy: 'memory'; id?: string};
type ExpoImageProps = ExpoImagePropsWithId | ExpoImagePropsMemoryOnly;
@@ -25,13 +27,13 @@ const ExpoImage = forwardRef<Image, ExpoImageProps>(({id, ...props}, ref) => {
* for filesystem path compatibility (avoiding special characters in directory names).
*/
const cachePath = useMemo(() => urlSafeBase64Encode(serverUrl), [serverUrl]);
- const source: ImageSource = useMemo(() => {
- if (typeof props.source === 'number') {
+ const source: ImageSource | string | number | ImageSource[] | string[] | SharedRefType<'image'> | null | undefined = useMemo(() => {
+ if (typeof props.source === 'number' || typeof props.source === 'string' || Array.isArray(props.source) || !props.source) {
return props.source;
}
// Only add cacheKey and cachePath if id is provided (i.e., not memory-only caching)
- if (id) {
+ if (id && typeof props.source === 'object' && 'uri' in props.source) {
return {
...props.source,
cacheKey: id,
@@ -43,13 +45,13 @@ const ExpoImage = forwardRef<Image, ExpoImageProps>(({id, ...props}, ref) => {
}, [id, props.source, cachePath]);
// Process placeholder to add cachePath and cacheKey if it has a uri
- const placeholder: ImageSource | undefined = useMemo(() => {
- if (!props.placeholder || typeof props.placeholder === 'number' || typeof props.placeholder === 'string') {
+ const placeholder: ImageSource | string | number | ImageSource[] | string[] | SharedRefType<'image'> | null | undefined = useMemo(() => {
+ if (!props.placeholder || typeof props.placeholder === 'number' || typeof props.placeholder === 'string' || Array.isArray(props.placeholder)) {
return props.placeholder;
}
// If placeholder has a uri and id is provided, add cachePath and cacheKey
- if (props.placeholder.uri && id) {
+ if (typeof props.placeholder === 'object' && 'uri' in props.placeholder && props.placeholder.uri && id) {
return {
...props.placeholder,
cacheKey: `${id}-thumb`,
@@ -74,13 +76,13 @@ ExpoImage.displayName = 'ExpoImage';
const ExpoImageBackground = ({id, ...props}: ExpoImageBackgroundProps) => {
const serverUrl = useServerUrl();
const cachePath = useMemo(() => urlSafeBase64Encode(serverUrl), [serverUrl]);
- const source: ImageSource = useMemo(() => {
- if (typeof props.source === 'number') {
+ const source: ImageSource | string | number | ImageSource[] | string[] | SharedRefType<'image'> | null | undefined = useMemo(() => {
+ if (typeof props.source === 'number' || typeof props.source === 'string' || Array.isArray(props.source) || !props.source) {
return props.source;
}
// Only add cacheKey and cachePath if id is provided (i.e., not memory-only caching)
- if (id) {
+ if (id && typeof props.source === 'object' && 'uri' in props.source) {
return {
...props.source,
cacheKey: id,
@@ -92,13 +94,13 @@ const ExpoImageBackground = ({id, ...props}: ExpoImageBackgroundProps) => {
}, [id, props.source, cachePath]);
// Process placeholder to add cachePath and cacheKey if it has a uri
- const placeholder: ImageSource | undefined = useMemo(() => {
- if (!props.placeholder || typeof props.placeholder === 'number' || typeof props.placeholder === 'string') {
+ const placeholder: ImageSource | string | number | ImageSource[] | string[] | SharedRefType<'image'> | null | undefined = useMemo(() => {
+ if (!props.placeholder || typeof props.placeholder === 'number' || typeof props.placeholder === 'string' || Array.isArray(props.placeholder)) {
return props.placeholder;
}
// If placeholder has a uri and id is provided, add cachePath and cacheKey
- if (props.placeholder.uri && id) {
+ if (typeof props.placeholder === 'object' && 'uri' in props.placeholder && props.placeholder.uri && id) {
return {
...props.placeholder,
cacheKey: `${id}-thumb`,
diff --git a/package.json b/package.json
index 80a6ffba49..47bb39cdcb 100644
--- a/package.json
+++ b/package.json
@@ -53,15 +53,17 @@
"deep-equal": "2.2.3",
"deepmerge": "4.3.1",
"emoji-regex": "10.4.0",
- "expo": "52.0.47",
+ "expo": "53.0.24",
"expo-application": "6.0.2",
+ "expo-constants": "17.1.7",
"expo-crypto": "14.0.2",
"expo-device": "7.0.3",
- "expo-image": "2.0.7",
- "expo-linear-gradient": "14.0.2",
+ "expo-file-system": "18.1.11",
+ "expo-image": "2.4.1",
+ "expo-linear-gradient": "14.1.5",
"expo-store-review": "8.0.1",
"expo-video-thumbnails": "9.0.3",
- "expo-web-browser": "14.0.2",
+ "expo-web-browser": "~14.2.0",
"fflate": "0.8.2",
"fuse.js": "7.1.0",
"html-entities": "2.6.0",
diff --git a/patches/expo-file-system+18.0.12.patch b/patches/expo-file-system+18.1.11.patch
similarity index 100%
rename from patches/expo-file-system+18.0.12.patch
rename to patches/expo-file-system+18.1.11.patch
diff --git a/patches/expo-image+2.0.7.patch b/patches/expo-image+2.4.1.patch
similarity index 92%
rename from patches/expo-image+2.0.7.patch
rename to patches/expo-image+2.4.1.patch
index 69520d0097..bece1d88a3 100644
--- a/patches/expo-image+2.0.7.patch
+++ b/patches/expo-image+2.4.1.patch
@@ -1,16 +1,3 @@
-diff --git a/node_modules/expo-image/android/build.gradle b/node_modules/expo-image/android/build.gradle
-index 11492a2..b6bb941 100644
---- a/node_modules/expo-image/android/build.gradle
-+++ b/node_modules/expo-image/android/build.gradle
-@@ -44,7 +44,7 @@ dependencies {
- kapt "com.github.bumptech.glide:compiler:${GLIDE_VERSION}"
- api 'com.caverock:androidsvg-aar:1.4'
-
-- implementation "com.github.penfeizhou.android.animation:glide-plugin:3.0.2"
-+ implementation("com.github.penfeizhou.android.animation:glide-plugin:3.0.3")
- implementation "com.github.bumptech.glide:avif-integration:${GLIDE_VERSION}"
-
- api 'com.github.bumptech.glide:okhttp3-integration:4.11.0'
diff --git a/node_modules/expo-image/android/src/main/java/expo/modules/image/ExpoImageAppGlideModule.kt b/node_modules/expo-image/android/src/main/java/expo/modules/image/ExpoImageAppGlideModule.kt
index 5735515..dbbb924 100644
--- a/node_modules/expo-image/android/src/main/java/expo/modules/image/ExpoImageAppGlideModule.kt
@@ -36,7 +23,7 @@ index 5735515..dbbb924 100644
}
}
diff --git a/node_modules/expo-image/android/src/main/java/expo/modules/image/ExpoImageModule.kt b/node_modules/expo-image/android/src/main/java/expo/modules/image/ExpoImageModule.kt
-index 73641a0..186fe54 100644
+index 0170d9b..169425c 100644
--- a/node_modules/expo-image/android/src/main/java/expo/modules/image/ExpoImageModule.kt
+++ b/node_modules/expo-image/android/src/main/java/expo/modules/image/ExpoImageModule.kt
@@ -148,13 +148,17 @@ class ExpoImageModule : Module() {
@@ -299,10 +286,10 @@ index 72ad8fa..60ceaac 100644
private fun getCustomHeaders(): Headers {
diff --git a/node_modules/expo-image/build/Image.d.ts b/node_modules/expo-image/build/Image.d.ts
-index 44ea175..14b20d9 100644
+index 765a3db..6982c6d 100644
--- a/node_modules/expo-image/build/Image.d.ts
+++ b/node_modules/expo-image/build/Image.d.ts
-@@ -33,6 +33,16 @@ export declare class Image extends React.PureComponent<ImageProps> {
+@@ -35,6 +35,16 @@ export declare class Image extends React.PureComponent<ImageProps> {
* finished prefetching.
*/
static prefetch(urls: string | string[], options?: ImagePrefetchOptions): Promise<boolean>;
@@ -319,7 +306,7 @@ index 44ea175..14b20d9 100644
/**
* Asynchronously clears all images stored in memory.
* @platform android
-@@ -46,11 +56,13 @@ export declare class Image extends React.PureComponent<ImageProps> {
+@@ -48,11 +58,13 @@ export declare class Image extends React.PureComponent<ImageProps> {
* Asynchronously clears all images from the disk cache.
* @platform android
* @platform ios
@@ -335,10 +322,10 @@ index 44ea175..14b20d9 100644
* Asynchronously checks if an image exists in the disk cache and resolves to
* the path of the cached image if it does.
diff --git a/node_modules/expo-image/build/Image.types.d.ts b/node_modules/expo-image/build/Image.types.d.ts
-index 493fd68..1f71756 100644
+index f690040..af43e4a 100644
--- a/node_modules/expo-image/build/Image.types.d.ts
+++ b/node_modules/expo-image/build/Image.types.d.ts
-@@ -46,6 +46,14 @@ export type ImageSource = {
+@@ -45,6 +45,14 @@ export type ImageSource = {
* If not provided, the `uri` is used also as the cache key.
*/
cacheKey?: string;
@@ -354,15 +341,16 @@ index 493fd68..1f71756 100644
* The max width of the viewport for which this source should be selected.
* Has no effect if `source` prop is not an array or has only 1 element.
diff --git a/node_modules/expo-image/ios/ExpoImage.podspec b/node_modules/expo-image/ios/ExpoImage.podspec
-index 21bef71..d662d23 100644
+index 40e2b49..695f137 100644
--- a/node_modules/expo-image/ios/ExpoImage.podspec
+++ b/node_modules/expo-image/ios/ExpoImage.podspec
-@@ -20,9 +20,7 @@ Pod::Spec.new do |s|
+@@ -20,10 +20,8 @@ Pod::Spec.new do |s|
s.dependency 'ExpoModulesCore'
- s.dependency 'SDWebImage', '~> 5.19.1'
+ s.dependency 'SDWebImage', '~> 5.21.0'
- s.dependency 'SDWebImageAVIFCoder', '~> 0.11.0'
s.dependency 'SDWebImageSVGCoder', '~> 1.7.0'
+ s.dependency 'SDWebImageWebPCoder', '~> 0.14.6'
- s.dependency 'libavif/libdav1d'
# Swift/Objective-C compatibility
@@ -384,7 +372,7 @@ index a0dacf9..36a2908 100644
if let maxSize {
context[.imageThumbnailPixelSize] = maxSize
diff --git a/node_modules/expo-image/ios/ImageModule.swift b/node_modules/expo-image/ios/ImageModule.swift
-index 4bab386..4d9ca4f 100644
+index 1451696..3985a30 100644
--- a/node_modules/expo-image/ios/ImageModule.swift
+++ b/node_modules/expo-image/ios/ImageModule.swift
@@ -2,7 +2,6 @@
@@ -395,7 +383,7 @@ index 4bab386..4d9ca4f 100644
import SDWebImageSVGCoder
public final class ImageModule: Module {
-@@ -150,6 +149,36 @@ public final class ImageModule: Module {
+@@ -170,6 +169,36 @@ public final class ImageModule: Module {
}
}
@@ -432,7 +420,7 @@ index 4bab386..4d9ca4f 100644
AsyncFunction("generateBlurhashAsync") { (url: URL, numberOfComponents: CGSize, promise: Promise) in
let downloader = SDWebImageDownloader()
let parsedNumberOfComponents = (Int(numberOfComponents.width), Int(numberOfComponents.height))
-@@ -170,9 +199,22 @@ public final class ImageModule: Module {
+@@ -190,9 +219,22 @@ public final class ImageModule: Module {
return true
}
@@ -458,10 +446,10 @@ index 4bab386..4d9ca4f 100644
}
}
-@@ -211,7 +253,6 @@ public final class ImageModule: Module {
+@@ -230,7 +272,6 @@ public final class ImageModule: Module {
+
static func registerCoders() {
- // By default Animated WebP is not supported
- SDImageCodersManager.shared.addCoder(SDImageAWebPCoder.shared)
+ SDImageCodersManager.shared.addCoder(WebPCoder.shared)
- SDImageCodersManager.shared.addCoder(SDImageAVIFCoder.shared)
SDImageCodersManager.shared.addCoder(SDImageSVGCoder.shared)
SDImageCodersManager.shared.addCoder(SDImageHEICCoder.shared)
@@ -481,19 +469,19 @@ index 88082fd..5025f0e 100644
return width * height * scale * scale
}
diff --git a/node_modules/expo-image/ios/ImageUtils.swift b/node_modules/expo-image/ios/ImageUtils.swift
-index 34f2231..a58943e 100644
+index e24e776..fc32c79 100644
--- a/node_modules/expo-image/ios/ImageUtils.swift
+++ b/node_modules/expo-image/ios/ImageUtils.swift
-@@ -172,7 +172,7 @@ func createCacheKeyFilter(_ cacheKey: String?) -> SDWebImageCacheKeyFilter? {
+@@ -158,7 +158,7 @@ func createCacheKeyFilter(_ cacheKey: String?) -> SDWebImageCacheKeyFilter? {
/**
Creates a default image context based on the source and the cache policy.
*/
--func createSDWebImageContext(forSource source: ImageSource, cachePolicy: ImageCachePolicy = .disk) -> SDWebImageContext {
-+func createSDWebImageContext(forSource source: ImageSource, cachePolicy: ImageCachePolicy = .disk, customCache: SDImageCache? = nil) -> SDWebImageContext {
+-func createSDWebImageContext(forSource source: ImageSource, cachePolicy: ImageCachePolicy = .disk, useAppleWebpCodec: Bool = true) -> SDWebImageContext {
++func createSDWebImageContext(forSource source: ImageSource, cachePolicy: ImageCachePolicy = .disk, customCache: SDImageCache? = nil, useAppleWebpCodec: Bool = true) -> SDWebImageContext {
var context = SDWebImageContext()
// Modify URL request to add headers.
-@@ -209,6 +209,12 @@ func createSDWebImageContext(forSource source: ImageSource, cachePolicy: ImageCa
+@@ -202,6 +202,12 @@ func createSDWebImageContext(forSource source: ImageSource, cachePolicy: ImageCa
// Some loaders (e.g. blurhash) may need access to the source.
context[ImageView.contextSourceKey] = source
@@ -507,7 +495,7 @@ index 34f2231..a58943e 100644
}
diff --git a/node_modules/expo-image/ios/ImageView.swift b/node_modules/expo-image/ios/ImageView.swift
-index 2ab4cba..0d423ea 100644
+index bb6f6a5..de3468b 100644
--- a/node_modules/expo-image/ios/ImageView.swift
+++ b/node_modules/expo-image/ios/ImageView.swift
@@ -8,6 +8,79 @@ import VisionKit
@@ -590,33 +578,33 @@ index 2ab4cba..0d423ea 100644
// swiftlint:disable:next type_body_length
public final class ImageView: ExpoView {
static let contextSourceKey = SDWebImageContextOption(rawValue: "source")
-@@ -129,7 +202,10 @@ public final class ImageView: ExpoView {
+@@ -152,7 +225,10 @@ public final class ImageView: ExpoView {
if sdImageView.image == nil {
sdImageView.contentMode = contentFit.toContentMode()
}
-- var context = createSDWebImageContext(forSource: source, cachePolicy: cachePolicy)
+- var context = createSDWebImageContext(forSource: source, cachePolicy: cachePolicy, useAppleWebpCodec: useAppleWebpCodec)
+
+ // Get custom cache if cachePath is specified
+ let customCache = CachePathManager.shared.getCacheForPath(source.cachePath)
-+ var context = createSDWebImageContext(forSource: source, cachePolicy: cachePolicy, customCache: customCache)
++ var context = createSDWebImageContext(forSource: source, cachePolicy: cachePolicy, customCache: customCache, useAppleWebpCodec: useAppleWebpCodec)
// Cancel currently running load requests.
cancelPendingOperation()
-@@ -311,7 +387,8 @@ public final class ImageView: ExpoView {
+@@ -337,7 +413,8 @@ public final class ImageView: ExpoView {
// to cache them or apply the same policy as with the proper image?
// Basically they are also cached in memory as the `placeholderImage` property,
// so just `disk` policy sounds like a good idea.
-- var context = createSDWebImageContext(forSource: placeholder, cachePolicy: .disk)
+- var context = createSDWebImageContext(forSource: placeholder, cachePolicy: .disk, useAppleWebpCodec: useAppleWebpCodec)
+ let customCache = CachePathManager.shared.getCacheForPath(placeholder.cachePath)
-+ var context = createSDWebImageContext(forSource: placeholder, cachePolicy: .disk, customCache: customCache)
++ var context = createSDWebImageContext(forSource: placeholder, cachePolicy: .disk, customCache: customCache, useAppleWebpCodec: useAppleWebpCodec)
let isPlaceholderHash = placeholder.isBlurhash || placeholder.isThumbhash
diff --git a/node_modules/expo-image/src/Image.tsx b/node_modules/expo-image/src/Image.tsx
-index 7721bd9..584cb02 100644
+index c52e711..c392133 100644
--- a/node_modules/expo-image/src/Image.tsx
+++ b/node_modules/expo-image/src/Image.tsx
-@@ -69,8 +69,18 @@ export class Image extends React.PureComponent<ImageProps> {
+@@ -70,8 +70,18 @@ export class Image extends React.PureComponent<ImageProps> {
* finished prefetching.
*/
static async prefetch(urls: string | string[], options?: ImagePrefetchOptions): Promise<boolean>;
@@ -636,7 +624,7 @@ index 7721bd9..584cb02 100644
options?: ImagePrefetchOptions['cachePolicy'] | ImagePrefetchOptions
): Promise<boolean> {
let cachePolicy: ImagePrefetchOptions['cachePolicy'] = 'memory-disk';
-@@ -85,7 +95,18 @@ export class Image extends React.PureComponent<ImageProps> {
+@@ -86,7 +96,18 @@ export class Image extends React.PureComponent<ImageProps> {
break;
}
@@ -655,12 +643,23 @@ index 7721bd9..584cb02 100644
+ }
}
+ /**
+@@ -109,8 +130,8 @@ export class Image extends React.PureComponent<ImageProps> {
+ * It may resolve to `false` on Android when the activity is no longer available.
+ * Resolves to `false` on Web.
+ */
+- static async clearDiskCache(): Promise<boolean> {
+- return await ImageModule.clearDiskCache();
++ static async clearDiskCache(path?: string): Promise<boolean> {
++ return await ImageModule.clearDiskCache(path);
+ }
+
/**
diff --git a/node_modules/expo-image/src/Image.types.ts b/node_modules/expo-image/src/Image.types.ts
-index 63445be..c67ad0c 100644
+index 0b4e7a5..efbe5ee 100644
--- a/node_modules/expo-image/src/Image.types.ts
+++ b/node_modules/expo-image/src/Image.types.ts
-@@ -51,6 +51,16 @@ export type ImageSource = {
+@@ -50,6 +50,16 @@ export type ImageSource = {
* If not provided, the `uri` is used also as the cache key.
*/
cacheKey?: string;
diff --git a/patches/expo-modules-core+2.2.3.patch b/patches/expo-modules-core+2.5.0.patch
similarity index 100%
rename from patches/expo-modules-core+2.2.3.patch
rename to patches/expo-modules-core+2.5.0.patch

View file

@ -0,0 +1,232 @@
#!/usr/bin/env node
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
/**
* Script to apply 16KB page size compatibility patches from a diff file.
* This automates the process of updating dependencies and applying code changes
* for Android 16KB page size support.
*
* Usage:
* node scripts/apply-16kb-pagesize-patch.js <diff-file> [--dry-run|--apply]
*
* Example:
* node scripts/apply-16kb-pagesize-patch.js 9325-full.diff --apply
*/
const {execSync} = require('child_process');
const fs = require('fs');
// ============================================================================
// CONSTANTS
// ============================================================================
const COLORS = {
reset: '\x1b[0m',
bright: '\x1b[1m',
green: '\x1b[32m',
yellow: '\x1b[33m',
blue: '\x1b[34m',
red: '\x1b[31m',
cyan: '\x1b[36m',
};
// Files to apply from the diff (excluding node_modules and package-lock.json)
// git apply will handle everything including file renames
const FILES_TO_EXCLUDE = [
'node_modules/*',
'package-lock.json',
];
// ============================================================================
// UTILITIES
// ============================================================================
function log(message, color = 'reset') {
// eslint-disable-next-line no-console
console.log(`${COLORS[color]}${message}${COLORS.reset}`);
}
function exec(command, options = {}) {
try {
return execSync(command, {
encoding: 'utf8',
stdio: options.silent ? 'pipe' : 'inherit',
...options,
});
} catch (error) {
if (!options.ignoreError) {
throw error;
}
return null;
}
}
// ============================================================================
// MAIN FUNCTIONS
// ============================================================================
function applyDiffChanges(diffPath, dryRun) {
log('\n📝 Applying changes from diff file', 'bright');
if (!fs.existsSync(diffPath)) {
log(`✗ Diff file not found: ${diffPath}`, 'red');
process.exit(1);
}
if (dryRun) {
log(' [DRY RUN] Would apply all changes using git apply', 'yellow');
log(' (excluding node_modules and package-lock.json)', 'yellow');
return;
}
try {
log(' Applying all changes (including file renames)...', 'cyan');
// Build exclude arguments
const excludeArgs = FILES_TO_EXCLUDE.map((pattern) => `--exclude='${pattern}'`).join(' ');
// Apply the diff, excluding node_modules and package-lock.json
exec(`git apply ${excludeArgs} ${diffPath}`, {silent: true});
log(' ✓ All changes applied successfully', 'green');
log(' ✓ Patch files renamed automatically', 'green');
} catch (error) {
log(` ✗ Failed to apply diff: ${error.message}`, 'red');
throw error;
}
}
function installUpdatedPackages(diffPath, dryRun) {
log('\n📦 Installing updated packages', 'bright');
if (dryRun) {
log(' [DRY RUN] Would run: npm install --ignore-scripts', 'yellow');
return;
}
try {
// Read package.json to get the list of changed packages
const packageJson = JSON.parse(fs.readFileSync('package.json', 'utf8'));
const dependencies = {...packageJson.dependencies, ...packageJson.devDependencies};
// Extract package names from diff
const diffContent = fs.readFileSync(diffPath, 'utf8');
const packageChanges = [];
const lines = diffContent.split('\n');
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
// Look for package.json dependency changes
if (line.startsWith('+ "expo') || line.startsWith('- "expo')) {
const match = line.match(/"([^"]+)":\s*"([^"]+)"/);
if (match && line.startsWith('+')) {
const [, pkgName] = match;
if (dependencies[pkgName] && !packageChanges.includes(pkgName)) {
packageChanges.push(pkgName);
}
}
}
}
if (packageChanges.length > 0) {
log(` Installing ${packageChanges.length} updated packages...`, 'cyan');
log(` Packages: ${packageChanges.join(', ')}`, 'cyan');
// Install only the changed packages to update package-lock.json
exec(`npm install ${packageChanges.join(' ')} --ignore-scripts`);
log(' ✓ Packages installed successfully', 'green');
} else {
log(' No package changes detected', 'yellow');
}
} catch (error) {
log(` ✗ Failed to install packages: ${error.message}`, 'red');
throw error;
}
}
function applyPatchFiles(dryRun) {
log('\n🔧 Applying patch files', 'bright');
if (dryRun) {
log(' [DRY RUN] Would run: npx patch-package', 'yellow');
return;
}
try {
exec('npx patch-package');
log(' ✓ Patch files applied successfully', 'green');
} catch (error) {
log(` ✗ Failed to apply patch files: ${error.message}`, 'red');
throw error;
}
}
function showSummary(dryRun) {
log('\n' + '='.repeat(70), 'cyan');
if (dryRun) {
log('DRY RUN COMPLETE', 'bright');
log('Run with --apply to actually apply the changes', 'yellow');
} else {
log('✓ ALL CHANGES APPLIED SUCCESSFULLY', 'green');
log('\n⚠ IMPORTANT:', 'yellow');
log('These changes are for Android builds ONLY', 'yellow');
log('DO NOT commit these changes to the repository', 'yellow');
log('\nNext steps:', 'bright');
log('1. Build your Android app', 'cyan');
log('2. After building, revert these changes with: git checkout .', 'cyan');
}
log('='.repeat(70), 'cyan');
}
// ============================================================================
// MAIN
// ============================================================================
function main() {
const args = process.argv.slice(2);
if (args.length === 0 || args.includes('--help') || args.includes('-h')) {
log('Usage: node scripts/apply-16kb-pagesize-patch.js <diff-file> [--dry-run|--apply]', 'bright');
log('\nOptions:', 'bright');
log(' --dry-run Preview changes without applying them (default)', 'cyan');
log(' --apply Actually apply the changes', 'cyan');
log(' --help, -h Show this help message', 'cyan');
log('\nExample:', 'bright');
log(' node scripts/apply-16kb-pagesize-patch.js 9325-full.diff --apply', 'cyan');
process.exit(0);
}
const diffPath = args[0];
const dryRun = !args.includes('--apply');
log('\n' + '='.repeat(70), 'cyan');
log('16KB PAGE SIZE PATCH APPLICATION', 'bright');
log('='.repeat(70), 'cyan');
log(`Diff file: ${diffPath}`, 'cyan');
log(`Mode: ${dryRun ? 'DRY RUN' : 'APPLY'}`, dryRun ? 'yellow' : 'green');
log('='.repeat(70), 'cyan');
try {
// Step 1: Apply diff changes using git apply (handles renames automatically)
applyDiffChanges(diffPath, dryRun);
// Step 2: Install updated packages
installUpdatedPackages(diffPath, dryRun);
// Step 3: Apply patch files
applyPatchFiles(dryRun);
// Show summary
showSummary(dryRun);
} catch (error) {
log('\n✗ Script failed with error:', 'red');
log(error.message, 'red');
process.exit(1);
}
}
main();

View file

@ -4,17 +4,32 @@ function execute() {
cd fastlane && NODE_ENV=production bundle exec fastlane $1 $2
}
function cleanupAndroid16kbPagesizePatch() {
# Only cleanup if we ran setup (SKIP_SETUP not set)
if [[ -z "$SKIP_SETUP" ]]; then
echo "Reverting 16KB page size patch changes..."
# Get the git root directory to ensure we're in the right place
local git_root=$(git rev-parse --show-toplevel)
cd "$git_root" || return
git checkout -- package.json package-lock.json app.json app/components/expo_image/index.tsx android/buildscript-gradle.lockfile patches/
git clean -fd patches/
echo "✓ Patch changes reverted"
fi
}
function apk() {
case $1 in
unsigned)
echo "Building Android unsigned app"
setup android
execute android unsigned
cleanupAndroid16kbPagesizePatch
;;
*)
echo "Building Android app"
setup android
execute android build
cleanupAndroid16kbPagesizePatch
esac
}
@ -55,7 +70,16 @@ function setup() {
if [[ -z "$SKIP_SETUP" ]]; then
npm run clean || exit 1
npm install --ignore-scripts || exit 1
# Apply 16KB page size patch for Android builds (includes npx patch-package)
if [[ "$1" == "android"* ]]; then
echo "Applying 16KB page size compatibility patch for Android"
npm run apply-16kb-pagesize-patch || exit 1
else
# For non-Android builds, just apply regular patches
npx patch-package || exit 1
fi
node node_modules/\@sentry/cli/scripts/install.js || exit 1
if [[ "$1" == "ios"* ]]; then