···12import java.io.FileOutputStream
13import java.net.URLEncoder
140000015class ExpoReceiveAndroidIntentsModule : Module() {
16 override fun definition() =
17 ModuleDefinition {
···23 }
2425 private fun handleIntent(intent: Intent?) {
26- if (appContext.currentActivity == null || intent == null) return
000002728- if (intent.action == Intent.ACTION_SEND) {
29- if (intent.type == "text/plain") {
30- handleTextIntent(intent)
31- } else if (intent.type.toString().startsWith("image/")) {
32- handleImageIntent(intent)
33- }
34- } else if (intent.action == Intent.ACTION_SEND_MULTIPLE) {
35- if (intent.type.toString().startsWith("image/")) {
36- handleImagesIntent(intent)
000037 }
38 }
39 }
···48 }
49 }
5051- private fun handleImageIntent(intent: Intent) {
00052 val uri =
53 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
54 intent.getParcelableExtra(Intent.EXTRA_STREAM, Uri::class.java)
55 } else {
56 intent.getParcelableExtra(Intent.EXTRA_STREAM)
57 }
58- if (uri == null) return
5960- handleImageIntents(listOf(uri))
0000061 }
6263- private fun handleImagesIntent(intent: Intent) {
64- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
65- intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM, Uri::class.java)?.let {
66- handleImageIntents(it.filterIsInstance<Uri>().take(4))
0000000000067 }
68- } else {
69- intent.getParcelableArrayListExtra<Uri>(Intent.EXTRA_STREAM)?.let {
70- handleImageIntents(it.filterIsInstance<Uri>().take(4))
0071 }
72 }
73 }
···93 }
94 }
95000000000000000000000096 private fun getImageInfo(uri: Uri): Map<String, Any> {
97 val bitmap = MediaStore.Images.Media.getBitmap(appContext.currentActivity?.contentResolver, uri)
98 // We have to save this so that we can access it later when uploading the image.
99 // createTempFile will automatically place a unique string between "img" and "temp.jpeg"
100- val file = File.createTempFile("img", "temp.jpeg", appContext.currentActivity?.cacheDir)
101 val out = FileOutputStream(file)
102 bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out)
103 out.flush()
···109 "path" to file.path.toString(),
110 )
111 }
00112113 // We will pas the width and height to the app here, since getting measurements
114 // on the RN side is a bit more involved, and we already have them here anyway.
···12import java.io.FileOutputStream
13import java.net.URLEncoder
1415+enum class AttachmentType {
16+ IMAGE,
17+ VIDEO,
18+}
19+20class ExpoReceiveAndroidIntentsModule : Module() {
21 override fun definition() =
22 ModuleDefinition {
···28 }
2930 private fun handleIntent(intent: Intent?) {
31+ if (appContext.currentActivity == null) return
32+ intent?.let {
33+ if (it.action == Intent.ACTION_SEND && it.type == "text/plain") {
34+ handleTextIntent(it)
35+ return
36+ }
3738+ val type =
39+ if (it.type.toString().startsWith("image/")) {
40+ AttachmentType.IMAGE
41+ } else if (it.type.toString().startsWith("video/")) {
42+ AttachmentType.VIDEO
43+ } else {
44+ return
45+ }
46+47+ if (it.action == Intent.ACTION_SEND) {
48+ handleAttachmentIntent(it, type)
49+ } else if (it.action == Intent.ACTION_SEND_MULTIPLE) {
50+ handleAttachmentsIntent(it, type)
51 }
52 }
53 }
···62 }
63 }
6465+ private fun handleAttachmentIntent(
66+ intent: Intent,
67+ type: AttachmentType,
68+ ) {
69 val uri =
70 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
71 intent.getParcelableExtra(Intent.EXTRA_STREAM, Uri::class.java)
72 } else {
73 intent.getParcelableExtra(Intent.EXTRA_STREAM)
74 }
07576+ uri?.let {
77+ when (type) {
78+ AttachmentType.IMAGE -> handleImageIntents(listOf(it))
79+ AttachmentType.VIDEO -> handleVideoIntents(listOf(it))
80+ }
81+ }
82 }
8384+ private fun handleAttachmentsIntent(
85+ intent: Intent,
86+ type: AttachmentType,
87+ ) {
88+ val uris =
89+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
90+ intent
91+ .getParcelableArrayListExtra(Intent.EXTRA_STREAM, Uri::class.java)
92+ ?.filterIsInstance<Uri>()
93+ ?.take(4)
94+ } else {
95+ intent
96+ .getParcelableArrayListExtra<Uri>(Intent.EXTRA_STREAM)
97+ ?.filterIsInstance<Uri>()
98+ ?.take(4)
99 }
100+101+ uris?.let {
102+ when (type) {
103+ AttachmentType.IMAGE -> handleImageIntents(it)
104+ else -> return
105 }
106 }
107 }
···127 }
128 }
129130+ private fun handleVideoIntents(uris: List<Uri>) {
131+ val uri = uris[0]
132+ // If there is no extension for the file, substringAfterLast returns the original string - not
133+ // null, so we check for that below
134+ // It doesn't actually matter what the extension is, so defaulting to mp4 is fine, even if the
135+ // video isn't actually an mp4
136+ var extension = uri.path?.substringAfterLast(".")
137+ if (extension == null || extension == uri.path) {
138+ extension = "mp4"
139+ }
140+ val file = createFile(extension)
141+142+ val out = FileOutputStream(file)
143+ appContext.currentActivity?.contentResolver?.openInputStream(uri)?.use {
144+ it.copyTo(out)
145+ }
146+ "bluesky://intent/compose?videoUri=${URLEncoder.encode(file.path, "UTF-8")}".toUri().let {
147+ val newIntent = Intent(Intent.ACTION_VIEW, it)
148+ appContext.currentActivity?.startActivity(newIntent)
149+ }
150+ }
151+152 private fun getImageInfo(uri: Uri): Map<String, Any> {
153 val bitmap = MediaStore.Images.Media.getBitmap(appContext.currentActivity?.contentResolver, uri)
154 // We have to save this so that we can access it later when uploading the image.
155 // createTempFile will automatically place a unique string between "img" and "temp.jpeg"
156+ val file = createFile("jpeg")
157 val out = FileOutputStream(file)
158 bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out)
159 out.flush()
···165 "path" to file.path.toString(),
166 )
167 }
168+169+ private fun createFile(extension: String): File = File.createTempFile(extension, "temp.$extension", appContext.currentActivity?.cacheDir)
170171 // We will pas the width and height to the app here, since getting measurements
172 // on the RN side is a bit more involved, and we already have them here anyway.