| author | |
| committer | |
| log | aab4049646ffa8b9bcff92562992e6c3a8554bf0 |
| tree | 03bf765b3785af152ea533f09917dead960928d6 |
| parent | b5a09e13fa464a8681e0bf9df404dd3c0afe8ac8 |
| signature | Signed by PGP key B5690EEEBB952194 |
5 files changed, 131 insertions(+), 131 deletions(-)
apps/mobile/package.json+1-1| ... | ... | @@ -97,7 +97,7 @@ |
| 97 | 97 | "expo-paste-input": "^0.1.15", |
| 98 | 98 | "expo-quick-actions": "^6.0.2", |
| 99 | 99 | "expo-secure-store": "~57.0.2", |
| 100 | "expo-sharing": "57.0.16", | |
| 100 | "expo-sharing": "57.0.17", | |
| 101 | 101 | "expo-splash-screen": "~57.0.8", |
| 102 | 102 | "expo-sqlite": "~57.0.2", |
| 103 | 103 | "expo-symbols": "~57.0.2", |
patches/expo-sharing@57.0.16.patch deleted-123| ... | ... | @@ -1,123 +0,0 @@ |
| 1 | diff --git a/android/src/main/java/expo/modules/sharing/SharingRecords.kt b/android/src/main/java/expo/modules/sharing/SharingRecords.kt | |
| 2 | index 0b87b53f632e82f9b4c09c066d5a67e4ab2525a4..65f1c57faef3ba8caac9e137341f2b8312bb5f86 100644 | |
| 3 | --- a/android/src/main/java/expo/modules/sharing/SharingRecords.kt | |
| 4 | +++ b/android/src/main/java/expo/modules/sharing/SharingRecords.kt | |
| 5 | @@ -52,7 +52,8 @@ enum class ContentType(val value: String) : Enumerable { | |
| 6 | internal data class SharePayload( | |
| 7 | @Field var value: String = "", | |
| 8 | @Field var shareType: ShareType = ShareType.Text, | |
| 9 | - @Field var mimeType: String = "text/plain" | |
| 10 | + @Field var mimeType: String = "text/plain", | |
| 11 | + @Field var originalName: String? = null | |
| 12 | ) : Record | |
| 13 | ||
| 14 | @OptimizedRecord | |
| 15 | diff --git a/android/src/main/java/expo/modules/sharing/dataParsers/SimpleShareIntentDataParser.kt b/android/src/main/java/expo/modules/sharing/dataParsers/SimpleShareIntentDataParser.kt | |
| 16 | index 8dd50e8f04022d183884a57e4d61a7e1711b9e49..481cdb4bc64ea5ae49919071f686324f6d56d55c 100644 | |
| 17 | --- a/android/src/main/java/expo/modules/sharing/dataParsers/SimpleShareIntentDataParser.kt | |
| 18 | +++ b/android/src/main/java/expo/modules/sharing/dataParsers/SimpleShareIntentDataParser.kt | |
| 19 | @@ -3,6 +3,7 @@ package expo.modules.sharing | |
| 20 | import android.content.Context | |
| 21 | import android.content.Intent | |
| 22 | import android.net.Uri | |
| 23 | +import android.provider.OpenableColumns | |
| 24 | ||
| 25 | internal class SimpleShareIntentDataParser { | |
| 26 | companion object { | |
| 27 | @@ -17,21 +18,26 @@ internal class SimpleShareIntentDataParser { | |
| 28 | } | |
| 29 | ||
| 30 | private fun handleSendAction(context: Context, intent: Intent, type: String): List<SharePayload> { | |
| 31 | - return if (type == "text/plain") { | |
| 32 | - val text = intent.getStringExtra(Intent.EXTRA_TEXT) ?: return emptyList() | |
| 33 | - val isUrl = android.util.Patterns.WEB_URL.matcher(text).matches() | |
| 34 | - | |
| 35 | - listOf( | |
| 36 | + val stream = intent.getParcelableExtraCompat<Uri>(Intent.EXTRA_STREAM) | |
| 37 | + val text = intent.getStringExtra(Intent.EXTRA_TEXT) | |
| 38 | + if (stream == null) { | |
| 39 | + if (!type.startsWith("text/") || text == null) return emptyList() | |
| 40 | + return listOf( | |
| 41 | SharePayload().apply { | |
| 42 | value = text | |
| 43 | - shareType = if (isUrl) ShareType.Url else ShareType.Text | |
| 44 | - mimeType = "text/plain" | |
| 45 | + shareType = if (android.util.Patterns.WEB_URL.matcher(text).matches()) ShareType.Url else ShareType.Text | |
| 46 | + mimeType = type | |
| 47 | } | |
| 48 | ) | |
| 49 | - } else { | |
| 50 | - val uri = intent.getParcelableExtraCompat<Uri>(Intent.EXTRA_STREAM) | |
| 51 | - listOfNotNull(uri?.let { createUriPayload(context, it, type) }) | |
| 52 | } | |
| 53 | + val filePayload = createUriPayload(context, stream, type) | |
| 54 | + if (text.isNullOrBlank()) return listOf(filePayload) | |
| 55 | + val textPayload = SharePayload().apply { | |
| 56 | + value = text | |
| 57 | + shareType = if (android.util.Patterns.WEB_URL.matcher(text).matches()) ShareType.Url else ShareType.Text | |
| 58 | + mimeType = "text/plain" | |
| 59 | + } | |
| 60 | + return listOf(textPayload, filePayload) | |
| 61 | } | |
| 62 | ||
| 63 | private fun handleSendMultipleAction(context: Context, intent: Intent, type: String): List<SharePayload> { | |
| 64 | @@ -41,10 +47,25 @@ internal class SimpleShareIntentDataParser { | |
| 65 | ||
| 66 | private fun createUriPayload(context: Context, uri: Uri, defaultType: String): SharePayload { | |
| 67 | val specificType = context.contentResolver.getType(uri) ?: defaultType | |
| 68 | + // A blank DISPLAY_NAME must stay null: consumers treat originalName as | |
| 69 | + // the attachment name, and an empty name fails contract validation. | |
| 70 | + val displayName = runCatching { | |
| 71 | + context.contentResolver.query( | |
| 72 | + uri, | |
| 73 | + arrayOf(OpenableColumns.DISPLAY_NAME), | |
| 74 | + null, | |
| 75 | + null, | |
| 76 | + null | |
| 77 | + )?.use { cursor -> | |
| 78 | + val column = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME) | |
| 79 | + if (column >= 0 && cursor.moveToFirst()) cursor.getString(column) else null | |
| 80 | + } | |
| 81 | + }.getOrNull()?.takeIf { it.isNotBlank() } | |
| 82 | return SharePayload().apply { | |
| 83 | value = uri.toString() | |
| 84 | - shareType = ShareType.fromMimeType(specificType) | |
| 85 | + shareType = if (specificType.startsWith("text/")) ShareType.File else ShareType.fromMimeType(specificType) | |
| 86 | mimeType = specificType | |
| 87 | + originalName = displayName | |
| 88 | } | |
| 89 | } | |
| 90 | } | |
| 91 | diff --git a/build/Sharing.types.d.ts b/build/Sharing.types.d.ts | |
| 92 | index e9820b061bddce91657ab7144fde98d0543a3b8e..364d63273cb3e209c6490de6dd869a01c8728fcc 100644 | |
| 93 | --- a/build/Sharing.types.d.ts | |
| 94 | +++ b/build/Sharing.types.d.ts | |
| 95 | @@ -77,6 +77,11 @@ export type SharePayload = { | |
| 96 | * @default 'text/plain' | |
| 97 | */ | |
| 98 | mimeType?: string; | |
| 99 | + /** | |
| 100 | + * The display name of a shared file, when the source app provided one. | |
| 101 | + * Populated on Android from the content resolver's `DISPLAY_NAME`. | |
| 102 | + */ | |
| 103 | + originalName?: string | null; | |
| 104 | }; | |
| 105 | export type BaseResolvedSharePayload = SharePayload & { | |
| 106 | /** | |
| 107 | diff --git a/src/Sharing.types.ts b/src/Sharing.types.ts | |
| 108 | index d9a5ad38f5fe2856b365eb91b71abd640314a5cc..21ea45f04b88cce272e2e02de24c5e4eb8157e82 100644 | |
| 109 | --- a/src/Sharing.types.ts | |
| 110 | +++ b/src/Sharing.types.ts | |
| 111 | @@ -85,6 +85,12 @@ export type SharePayload = { | |
| 112 | * @default 'text/plain' | |
| 113 | */ | |
| 114 | mimeType?: string; | |
| 115 | + | |
| 116 | + /** | |
| 117 | + * The display name of a shared file, when the source app provided one. | |
| 118 | + * Populated on Android from the content resolver's `DISPLAY_NAME`. | |
| 119 | + */ | |
| 120 | + originalName?: string | null; | |
| 121 | }; | |
| 122 | ||
| 123 | export type BaseResolvedSharePayload = SharePayload & { |
patches/expo-sharing@57.0.17.patch created+123| ... | ... | @@ -0,0 +1,123 @@ |
| 1 | diff --git a/android/src/main/java/expo/modules/sharing/SharingRecords.kt b/android/src/main/java/expo/modules/sharing/SharingRecords.kt | |
| 2 | index 0b87b53f632e82f9b4c09c066d5a67e4ab2525a4..65f1c57faef3ba8caac9e137341f2b8312bb5f86 100644 | |
| 3 | --- a/android/src/main/java/expo/modules/sharing/SharingRecords.kt | |
| 4 | +++ b/android/src/main/java/expo/modules/sharing/SharingRecords.kt | |
| 5 | @@ -52,7 +52,8 @@ enum class ContentType(val value: String) : Enumerable { | |
| 6 | internal data class SharePayload( | |
| 7 | @Field var value: String = "", | |
| 8 | @Field var shareType: ShareType = ShareType.Text, | |
| 9 | - @Field var mimeType: String = "text/plain" | |
| 10 | + @Field var mimeType: String = "text/plain", | |
| 11 | + @Field var originalName: String? = null | |
| 12 | ) : Record | |
| 13 | ||
| 14 | @OptimizedRecord | |
| 15 | diff --git a/android/src/main/java/expo/modules/sharing/dataParsers/SimpleShareIntentDataParser.kt b/android/src/main/java/expo/modules/sharing/dataParsers/SimpleShareIntentDataParser.kt | |
| 16 | index 8dd50e8f04022d183884a57e4d61a7e1711b9e49..481cdb4bc64ea5ae49919071f686324f6d56d55c 100644 | |
| 17 | --- a/android/src/main/java/expo/modules/sharing/dataParsers/SimpleShareIntentDataParser.kt | |
| 18 | +++ b/android/src/main/java/expo/modules/sharing/dataParsers/SimpleShareIntentDataParser.kt | |
| 19 | @@ -3,6 +3,7 @@ package expo.modules.sharing | |
| 20 | import android.content.Context | |
| 21 | import android.content.Intent | |
| 22 | import android.net.Uri | |
| 23 | +import android.provider.OpenableColumns | |
| 24 | ||
| 25 | internal class SimpleShareIntentDataParser { | |
| 26 | companion object { | |
| 27 | @@ -17,21 +18,26 @@ internal class SimpleShareIntentDataParser { | |
| 28 | } | |
| 29 | ||
| 30 | private fun handleSendAction(context: Context, intent: Intent, type: String): List<SharePayload> { | |
| 31 | - return if (type == "text/plain") { | |
| 32 | - val text = intent.getStringExtra(Intent.EXTRA_TEXT) ?: return emptyList() | |
| 33 | - val isUrl = android.util.Patterns.WEB_URL.matcher(text).matches() | |
| 34 | - | |
| 35 | - listOf( | |
| 36 | + val stream = intent.getParcelableExtraCompat<Uri>(Intent.EXTRA_STREAM) | |
| 37 | + val text = intent.getStringExtra(Intent.EXTRA_TEXT) | |
| 38 | + if (stream == null) { | |
| 39 | + if (!type.startsWith("text/") || text == null) return emptyList() | |
| 40 | + return listOf( | |
| 41 | SharePayload().apply { | |
| 42 | value = text | |
| 43 | - shareType = if (isUrl) ShareType.Url else ShareType.Text | |
| 44 | - mimeType = "text/plain" | |
| 45 | + shareType = if (android.util.Patterns.WEB_URL.matcher(text).matches()) ShareType.Url else ShareType.Text | |
| 46 | + mimeType = type | |
| 47 | } | |
| 48 | ) | |
| 49 | - } else { | |
| 50 | - val uri = intent.getParcelableExtraCompat<Uri>(Intent.EXTRA_STREAM) | |
| 51 | - listOfNotNull(uri?.let { createUriPayload(context, it, type) }) | |
| 52 | } | |
| 53 | + val filePayload = createUriPayload(context, stream, type) | |
| 54 | + if (text.isNullOrBlank()) return listOf(filePayload) | |
| 55 | + val textPayload = SharePayload().apply { | |
| 56 | + value = text | |
| 57 | + shareType = if (android.util.Patterns.WEB_URL.matcher(text).matches()) ShareType.Url else ShareType.Text | |
| 58 | + mimeType = "text/plain" | |
| 59 | + } | |
| 60 | + return listOf(textPayload, filePayload) | |
| 61 | } | |
| 62 | ||
| 63 | private fun handleSendMultipleAction(context: Context, intent: Intent, type: String): List<SharePayload> { | |
| 64 | @@ -41,10 +47,25 @@ internal class SimpleShareIntentDataParser { | |
| 65 | ||
| 66 | private fun createUriPayload(context: Context, uri: Uri, defaultType: String): SharePayload { | |
| 67 | val specificType = context.contentResolver.getType(uri) ?: defaultType | |
| 68 | + // A blank DISPLAY_NAME must stay null: consumers treat originalName as | |
| 69 | + // the attachment name, and an empty name fails contract validation. | |
| 70 | + val displayName = runCatching { | |
| 71 | + context.contentResolver.query( | |
| 72 | + uri, | |
| 73 | + arrayOf(OpenableColumns.DISPLAY_NAME), | |
| 74 | + null, | |
| 75 | + null, | |
| 76 | + null | |
| 77 | + )?.use { cursor -> | |
| 78 | + val column = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME) | |
| 79 | + if (column >= 0 && cursor.moveToFirst()) cursor.getString(column) else null | |
| 80 | + } | |
| 81 | + }.getOrNull()?.takeIf { it.isNotBlank() } | |
| 82 | return SharePayload().apply { | |
| 83 | value = uri.toString() | |
| 84 | - shareType = ShareType.fromMimeType(specificType) | |
| 85 | + shareType = if (specificType.startsWith("text/")) ShareType.File else ShareType.fromMimeType(specificType) | |
| 86 | mimeType = specificType | |
| 87 | + originalName = displayName | |
| 88 | } | |
| 89 | } | |
| 90 | } | |
| 91 | diff --git a/build/Sharing.types.d.ts b/build/Sharing.types.d.ts | |
| 92 | index e9820b061bddce91657ab7144fde98d0543a3b8e..364d63273cb3e209c6490de6dd869a01c8728fcc 100644 | |
| 93 | --- a/build/Sharing.types.d.ts | |
| 94 | +++ b/build/Sharing.types.d.ts | |
| 95 | @@ -77,6 +77,11 @@ export type SharePayload = { | |
| 96 | * @default 'text/plain' | |
| 97 | */ | |
| 98 | mimeType?: string; | |
| 99 | + /** | |
| 100 | + * The display name of a shared file, when the source app provided one. | |
| 101 | + * Populated on Android from the content resolver's `DISPLAY_NAME`. | |
| 102 | + */ | |
| 103 | + originalName?: string | null; | |
| 104 | }; | |
| 105 | export type BaseResolvedSharePayload = SharePayload & { | |
| 106 | /** | |
| 107 | diff --git a/src/Sharing.types.ts b/src/Sharing.types.ts | |
| 108 | index d9a5ad38f5fe2856b365eb91b71abd640314a5cc..21ea45f04b88cce272e2e02de24c5e4eb8157e82 100644 | |
| 109 | --- a/src/Sharing.types.ts | |
| 110 | +++ b/src/Sharing.types.ts | |
| 111 | @@ -85,6 +85,12 @@ export type SharePayload = { | |
| 112 | * @default 'text/plain' | |
| 113 | */ | |
| 114 | mimeType?: string; | |
| 115 | + | |
| 116 | + /** | |
| 117 | + * The display name of a shared file, when the source app provided one. | |
| 118 | + * Populated on Android from the content resolver's `DISPLAY_NAME`. | |
| 119 | + */ | |
| 120 | + originalName?: string | null; | |
| 121 | }; | |
| 122 | ||
| 123 | export type BaseResolvedSharePayload = SharePayload & { |
pnpm-lock.yaml+6-6| ... | ... | @@ -93,7 +93,7 @@ patchedDependencies: |
| 93 | 93 | '@react-navigation/native-stack@7.17.6': e667c3cef8c78bb9ff4882ee5bd23a432247b843060a9499eb5f07e9e2295552 |
| 94 | 94 | effect@4.0.0-beta.103: af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6 |
| 95 | 95 | expo-audio@57.0.4: fa9a3e0442ed395d4071bb406e08c3a471c9a84700bdfa0b9ad7ff144c96041a |
| 96 | expo-sharing@57.0.16: 8d2e3b10eb3f52036a9a086800180ec6cebf3b75bccc5b1775117a7244d4ac45 | |
| 96 | expo-sharing@57.0.17: 8d2e3b10eb3f52036a9a086800180ec6cebf3b75bccc5b1775117a7244d4ac45 | |
| 97 | 97 | react-native-gesture-handler@2.32.0: 808eb26f9e57cf4945efd3985af4d9c764da6f91f4c9764433cc868602bbf4d3 |
| 98 | 98 | react-native-keyboard-controller@1.21.13: 6e4339347bc5bb3c9ea67d85ff5c814058b211c5750f247aba59d07869a2e787 |
| 99 | 99 | react-native-nitro-modules@0.35.9: 825622aae63a8fb5b904f3c77908a0e216261d727ea171709f2c0b6088422675 |
| ... | ... | @@ -368,8 +368,8 @@ importers: |
| 368 | 368 | specifier: ~57.0.2 |
| 369 | 369 | version: 57.0.2(expo@57.0.18) |
| 370 | 370 | expo-sharing: |
| 371 | specifier: 57.0.16 | |
| 372 | version: 57.0.16(patch_hash=8d2e3b10eb3f52036a9a086800180ec6cebf3b75bccc5b1775117a7244d4ac45)(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3)(typescript@6.0.3) | |
| 371 | specifier: 57.0.17 | |
| 372 | version: 57.0.17(patch_hash=8d2e3b10eb3f52036a9a086800180ec6cebf3b75bccc5b1775117a7244d4ac45)(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3)(typescript@6.0.3) | |
| 373 | 373 | expo-splash-screen: |
| 374 | 374 | specifier: ~57.0.8 |
| 375 | 375 | version: 57.0.8(expo@57.0.18)(typescript@6.0.3) |
| ... | ... | @@ -6676,8 +6676,8 @@ packages: |
| 6676 | 6676 | resolution: {integrity: sha512-aK+LdKzauHSGmsOStZtyxdzv0zWssCkxTw3m4QuOhfDSJsZaMRTd9O41d8ixU/QfELTbaJ0oRNcF7JFV/7O9YQ==} |
| 6677 | 6677 | engines: {node: '>=20.16.0'} |
| 6678 | 6678 | |
| 6679 | expo-sharing@57.0.16: | |
| 6680 | resolution: {integrity: sha512-Z4ZFYLP8+EqIdUAiERYRI4/r7rtZDCRQ8Lj6jDG0xPF19B8nsFhYMgh7uyic+WulFEr+Xn7FeWgSDAuufkOyzw==} | |
| 6679 | expo-sharing@57.0.17: | |
| 6680 | resolution: {integrity: sha512-p2B4SMeNsOv6hm1NkrxRlncjwu9mmLfi0drLaEyX13Rxn4DdDFPhuaezpOK7XLogTsmWGpfR46uq6oHMvSxbfA==} | |
| 6681 | 6681 | peerDependencies: |
| 6682 | 6682 | expo: '*' |
| 6683 | 6683 | react: '*' |
| ... | ... | @@ -16613,7 +16613,7 @@ snapshots: |
| 16613 | 16613 | |
| 16614 | 16614 | expo-server@57.0.3: {} |
| 16615 | 16615 | |
| 16616 | expo-sharing@57.0.16(patch_hash=8d2e3b10eb3f52036a9a086800180ec6cebf3b75bccc5b1775117a7244d4ac45)(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3)(typescript@6.0.3): | |
| 16616 | expo-sharing@57.0.17(patch_hash=8d2e3b10eb3f52036a9a086800180ec6cebf3b75bccc5b1775117a7244d4ac45)(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3)(typescript@6.0.3): | |
| 16617 | 16617 | dependencies: |
| 16618 | 16618 | '@expo/config-plugins': 57.0.9(typescript@6.0.3) |
| 16619 | 16619 | '@expo/config-types': 57.0.2 |
pnpm-workspace.yaml+1-1| ... | ... | @@ -155,7 +155,7 @@ patchedDependencies: |
| 155 | 155 | "@react-navigation/native-stack@7.17.6": patches/@react-navigation%2Fnative-stack@7.17.6.patch |
| 156 | 156 | effect@4.0.0-beta.103: patches/effect@4.0.0-beta.103.patch |
| 157 | 157 | expo-audio@57.0.4: patches/expo-audio@57.0.4.patch |
| 158 | expo-sharing@57.0.16: patches/expo-sharing@57.0.16.patch | |
| 158 | expo-sharing@57.0.17: patches/expo-sharing@57.0.17.patch | |
| 159 | 159 | react-native-gesture-handler@2.32.0: patches/react-native-gesture-handler@2.32.0.patch |
| 160 | 160 | react-native-keyboard-controller@1.21.13: patches/react-native-keyboard-controller@1.21.13.patch |
| 161 | 161 | react-native-nitro-modules@0.35.9: patches/react-native-nitro-modules@0.35.9.patch |