@tbvjaos510/react-native-paste-input 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. package/.circleci/config.yml +130 -0
  2. package/LICENSE +21 -0
  3. package/README.md +73 -0
  4. package/android/.project +17 -0
  5. package/android/.settings/org.eclipse.buildship.core.prefs +13 -0
  6. package/android/build.gradle +94 -0
  7. package/android/generated/java/com/facebook/react/viewmanagers/PasteTextInputManagerDelegate.java +236 -0
  8. package/android/generated/java/com/facebook/react/viewmanagers/PasteTextInputManagerInterface.java +84 -0
  9. package/android/generated/jni/CMakeLists.txt +36 -0
  10. package/android/generated/jni/PasteTextInputSpecs-generated.cpp +27 -0
  11. package/android/generated/jni/PasteTextInputSpecs.h +28 -0
  12. package/android/generated/jni/react/renderer/components/PasteTextInputSpecs/ComponentDescriptors.cpp +22 -0
  13. package/android/generated/jni/react/renderer/components/PasteTextInputSpecs/ComponentDescriptors.h +166 -0
  14. package/android/generated/jni/react/renderer/components/PasteTextInputSpecs/EventEmitters.cpp +183 -0
  15. package/android/generated/jni/react/renderer/components/PasteTextInputSpecs/EventEmitters.h +148 -0
  16. package/android/generated/jni/react/renderer/components/PasteTextInputSpecs/PasteTextInputSpecsJSI-generated.cpp +17 -0
  17. package/android/generated/jni/react/renderer/components/PasteTextInputSpecs/PasteTextInputSpecsJSI.h +19 -0
  18. package/android/generated/jni/react/renderer/components/PasteTextInputSpecs/Props.cpp +640 -0
  19. package/android/generated/jni/react/renderer/components/PasteTextInputSpecs/Props.h +144 -0
  20. package/android/generated/jni/react/renderer/components/PasteTextInputSpecs/ShadowNodes.cpp +247 -0
  21. package/android/generated/jni/react/renderer/components/PasteTextInputSpecs/ShadowNodes.h +95 -0
  22. package/android/generated/jni/react/renderer/components/PasteTextInputSpecs/States.cpp +14 -0
  23. package/android/generated/jni/react/renderer/components/PasteTextInputSpecs/States.h +19 -0
  24. package/android/gradle.properties +6 -0
  25. package/android/src/main/java/com/mattermost/pasteinputtext/IPasteInputListener.kt +8 -0
  26. package/android/src/main/java/com/mattermost/pasteinputtext/PasteInputActionCallback.kt +72 -0
  27. package/android/src/main/java/com/mattermost/pasteinputtext/PasteInputEditText.kt +60 -0
  28. package/android/src/main/java/com/mattermost/pasteinputtext/PasteInputFileFromUrl.kt +50 -0
  29. package/android/src/main/java/com/mattermost/pasteinputtext/PasteInputListener.kt +84 -0
  30. package/android/src/main/java/com/mattermost/pasteinputtext/PasteTextInputManager.kt +72 -0
  31. package/android/src/main/java/com/mattermost/pasteinputtext/PasteTextInputPackage.kt +14 -0
  32. package/android/src/main/java/com/mattermost/pasteinputtext/PasteTextInputPasteEvent.java +41 -0
  33. package/android/src/main/java/com/mattermost/pasteinputtext/RealPathUtil.kt +174 -0
  34. package/ios/NSData+MimeType.h +20 -0
  35. package/ios/NSData+MimeType.m +59 -0
  36. package/ios/PasteInput-Bridging-Header.h +1 -0
  37. package/ios/PasteInput.xcodeproj/project.pbxproj +319 -0
  38. package/ios/PasteInputTextView.h +20 -0
  39. package/ios/PasteInputTextView.m +68 -0
  40. package/ios/PasteInputView.h +18 -0
  41. package/ios/PasteInputView.m +96 -0
  42. package/ios/PasteTextInput.h +13 -0
  43. package/ios/PasteTextInput.mm +726 -0
  44. package/ios/PasteTextInputManager.mm +171 -0
  45. package/ios/Swime/MimeType.h +70 -0
  46. package/ios/Swime/MimeType.m +701 -0
  47. package/ios/Swime/Swime.h +14 -0
  48. package/ios/Swime/Swime.m +28 -0
  49. package/ios/Swime/SwimeProxy.h +18 -0
  50. package/ios/Swime/SwimeProxy.m +66 -0
  51. package/ios/Swime/SwimeUtils.h +12 -0
  52. package/ios/Swime/SwimeUtils.m +23 -0
  53. package/ios/UIImage+ImageEffects.h +112 -0
  54. package/ios/UIImage+ImageEffects.m +310 -0
  55. package/ios/UIImage+vImageScaling.h +16 -0
  56. package/ios/UIImage+vImageScaling.m +48 -0
  57. package/ios/UIPasteboard+GetImageInfo.h +19 -0
  58. package/ios/UIPasteboard+GetImageInfo.m +98 -0
  59. package/ios/generated/PasteTextInputSpecs/ComponentDescriptors.cpp +22 -0
  60. package/ios/generated/PasteTextInputSpecs/ComponentDescriptors.h +42 -0
  61. package/ios/generated/PasteTextInputSpecs/EventEmitters.cpp +41 -0
  62. package/ios/generated/PasteTextInputSpecs/EventEmitters.h +37 -0
  63. package/ios/generated/PasteTextInputSpecs/PasteTextInputSpecs-generated.mm +16 -0
  64. package/ios/generated/PasteTextInputSpecs/PasteTextInputSpecs.h +38 -0
  65. package/ios/generated/PasteTextInputSpecs/Props.cpp +142 -0
  66. package/ios/generated/PasteTextInputSpecs/Props.h +81 -0
  67. package/ios/generated/PasteTextInputSpecs/RCTComponentViewHelpers.h +106 -0
  68. package/ios/generated/PasteTextInputSpecs/ShadowNodes.cpp +127 -0
  69. package/ios/generated/PasteTextInputSpecs/ShadowNodes.h +85 -0
  70. package/ios/generated/PasteTextInputSpecs/States.cpp +16 -0
  71. package/ios/generated/PasteTextInputSpecs/States.h +53 -0
  72. package/ios/generated/PasteTextInputSpecsJSI-generated.cpp +17 -0
  73. package/ios/generated/PasteTextInputSpecsJSI.h +19 -0
  74. package/lib/commonjs/PasteTextInput.js +446 -0
  75. package/lib/commonjs/PasteTextInput.js.map +1 -0
  76. package/lib/commonjs/PasteTextInputNativeComponent.ts +277 -0
  77. package/lib/commonjs/index.js +25 -0
  78. package/lib/commonjs/index.js.map +1 -0
  79. package/lib/commonjs/module.d.js +2 -0
  80. package/lib/commonjs/module.d.js.map +1 -0
  81. package/lib/commonjs/package.json +1 -0
  82. package/lib/commonjs/types.js +6 -0
  83. package/lib/commonjs/types.js.map +1 -0
  84. package/lib/module/PasteTextInput.js +440 -0
  85. package/lib/module/PasteTextInput.js.map +1 -0
  86. package/lib/module/PasteTextInputNativeComponent.ts +277 -0
  87. package/lib/module/index.js +9 -0
  88. package/lib/module/index.js.map +1 -0
  89. package/lib/module/module.d.js +2 -0
  90. package/lib/module/module.d.js.map +1 -0
  91. package/lib/module/types.js +4 -0
  92. package/lib/module/types.js.map +1 -0
  93. package/lib/typescript/src/PasteTextInput.d.ts +5 -0
  94. package/lib/typescript/src/PasteTextInput.d.ts.map +1 -0
  95. package/lib/typescript/src/PasteTextInputNativeComponent.d.ts +168 -0
  96. package/lib/typescript/src/PasteTextInputNativeComponent.d.ts.map +1 -0
  97. package/lib/typescript/src/index.d.ts +6 -0
  98. package/lib/typescript/src/index.d.ts.map +1 -0
  99. package/lib/typescript/src/types.d.ts +56 -0
  100. package/lib/typescript/src/types.d.ts.map +1 -0
  101. package/package.json +140 -0
  102. package/react-native-paste-input.podspec +20 -0
  103. package/react-native.config.js +13 -0
  104. package/src/PasteTextInput.tsx +615 -0
  105. package/src/PasteTextInputNativeComponent.ts +277 -0
  106. package/src/index.ts +13 -0
  107. package/src/module.d.ts +4 -0
  108. package/src/types.ts +71 -0
@@ -0,0 +1,50 @@
1
+ package com.mattermost.pasteinputtext
2
+
3
+ import com.facebook.react.bridge.Arguments
4
+ import com.facebook.react.bridge.WritableArray
5
+ import com.facebook.react.bridge.WritableMap
6
+ import com.facebook.react.uimanager.events.EventDispatcher
7
+ import com.facebook.react.views.textinput.ReactEditText
8
+ import java.io.IOException
9
+ import java.net.URL
10
+
11
+ class PasteInputFileFromUrl(target: ReactEditText, uri: String, surfaceId: Int, eventDispatcher: EventDispatcher?): Runnable {
12
+ private val mTarget = target
13
+ private val mUri = uri
14
+ private val mEventDispatcher = eventDispatcher
15
+ private val mSurfaceId = surfaceId
16
+
17
+ override fun run() {
18
+ var files: WritableArray? = null
19
+ var error: WritableMap? = null
20
+
21
+ try {
22
+ val url = URL(mUri)
23
+ val conn = url.openConnection()
24
+ val mimeType = conn.getHeaderField("Content-Type")
25
+ val fileSize = java.lang.Long.parseLong(conn.getHeaderField("Content-Length"))
26
+ val contentDisposition = conn.getHeaderField("Content-Disposition")
27
+ val startIndex = contentDisposition.indexOf("filename=\"") + 10
28
+ val endIndex = contentDisposition.length - 1
29
+ val fileName = contentDisposition.substring(startIndex, endIndex)
30
+ val file = Arguments.createMap()
31
+
32
+ file.putString("type", mimeType)
33
+ file.putDouble("fileSize", fileSize.toDouble())
34
+ file.putString("fileName", fileName)
35
+ file.putString("uri", mUri)
36
+
37
+ files = Arguments.createArray()
38
+ files.pushMap(file)
39
+ } catch (e: IOException) {
40
+ error = Arguments.createMap()
41
+ error.putString("message", e.localizedMessage)
42
+ }
43
+
44
+ val event = Arguments.createMap()
45
+ event.putArray("data", files)
46
+ event.putMap("error", error)
47
+
48
+ mEventDispatcher?.dispatchEvent(PasteTextInputPasteEvent(mSurfaceId, mTarget.id, event))
49
+ }
50
+ }
@@ -0,0 +1,84 @@
1
+ package com.mattermost.pasteinputtext
2
+
3
+ import android.content.ClipboardManager
4
+ import android.content.Context
5
+ import android.net.Uri
6
+ import android.util.Patterns
7
+ import android.webkit.MimeTypeMap
8
+ import android.webkit.URLUtil
9
+ import com.facebook.react.bridge.Arguments
10
+ import com.facebook.react.bridge.ReactContext
11
+ import com.facebook.react.bridge.WritableArray
12
+ import com.facebook.react.bridge.WritableMap
13
+ import com.facebook.react.uimanager.events.EventDispatcher
14
+ import java.io.FileNotFoundException
15
+
16
+ class PasteInputListener(editText: PasteInputEditText, surfaceId: Int) : IPasteInputListener {
17
+ private val mEditText = editText
18
+ private val mSurfaceId = surfaceId
19
+
20
+ override fun onPaste(itemUri: Uri, eventDispatcher: EventDispatcher?) {
21
+ val reactContext = mEditText.context as ReactContext
22
+ reactContext.contentResolver.getType(itemUri) ?: return
23
+
24
+ var uriString: String = itemUri.toString()
25
+ val mimeType: String
26
+ val fileSize: Long
27
+ var files: WritableArray? = null
28
+ var error: WritableMap? = null
29
+
30
+ // Special handle for Google docs
31
+ if (uriString == "content://com.google.android.apps.docs.editors.kix.editors.clipboard") {
32
+ val clipboardManager = reactContext.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
33
+ val clipData = clipboardManager.primaryClip ?: return
34
+ val item = clipData.getItemAt(0) ?: return
35
+ val htmlText = item.htmlText
36
+
37
+ // Find uri from html
38
+ val matcher = Patterns.WEB_URL.matcher(htmlText)
39
+ if (matcher.find()) {
40
+ uriString = htmlText.substring(matcher.start(1), matcher.end())
41
+ }
42
+ } else if (uriString.startsWith("http")) {
43
+ val pastImageFromUrlThread = Thread(PasteInputFileFromUrl(
44
+ mEditText,
45
+ uriString,
46
+ mSurfaceId,
47
+ eventDispatcher
48
+ ))
49
+ pastImageFromUrlThread.start()
50
+ return
51
+ } else {
52
+ uriString = RealPathUtil.getRealPathFromURI(reactContext, itemUri) ?: return
53
+ }
54
+
55
+ val extension: String = MimeTypeMap.getFileExtensionFromUrl(uriString) ?: return
56
+ mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension) ?: return
57
+ val fileName: String = URLUtil.guessFileName(uriString, null, mimeType)
58
+
59
+ try {
60
+ val contentResolver = reactContext.contentResolver
61
+ val assetFileDescriptor = contentResolver.openAssetFileDescriptor(itemUri, "r") ?: return
62
+ val file = Arguments.createMap()
63
+
64
+ files = Arguments.createArray()
65
+ fileSize = assetFileDescriptor.length
66
+ file.putString("type", mimeType)
67
+ file.putDouble("fileSize", fileSize.toDouble())
68
+ file.putString("fileName", fileName)
69
+ file.putString("uri", "file://$uriString")
70
+
71
+ files.pushMap(file)
72
+ assetFileDescriptor.close()
73
+ } catch (e: FileNotFoundException) {
74
+ error = Arguments.createMap()
75
+ error.putString("message", e.localizedMessage)
76
+ }
77
+
78
+ val event = Arguments.createMap()
79
+ event.putArray("data", files)
80
+ event.putMap("error", error)
81
+
82
+ eventDispatcher?.dispatchEvent(PasteTextInputPasteEvent(mSurfaceId, mEditText.id, event))
83
+ }
84
+ }
@@ -0,0 +1,72 @@
1
+ package com.mattermost.pasteinputtext
2
+
3
+ import android.text.InputType
4
+ import com.facebook.react.bridge.ReactApplicationContext
5
+ import com.facebook.react.bridge.ReactContext
6
+ import com.facebook.react.common.MapBuilder
7
+ import com.facebook.react.module.annotations.ReactModule
8
+ import com.facebook.react.uimanager.ThemedReactContext
9
+ import com.facebook.react.uimanager.UIManagerHelper
10
+ import com.facebook.react.uimanager.annotations.ReactProp
11
+ import com.facebook.react.uimanager.events.EventDispatcher
12
+ import com.facebook.react.views.textinput.ReactEditText
13
+ import com.facebook.react.views.textinput.ReactTextInputManager
14
+
15
+ @ReactModule(name = "PasteTextInput")
16
+ class PasteTextInputManager(context: ReactApplicationContext) : ReactTextInputManager() {
17
+ private var disableCopyPaste: Boolean = false
18
+ private val mContext = context
19
+
20
+ override fun getName(): String = NAME
21
+
22
+ @ReactProp(name = "disableCopyPaste", defaultBoolean = false)
23
+ fun setDisableCopyPaste(editText: PasteInputEditText, disabled: Boolean) {
24
+ disableCopyPaste = disabled
25
+ val eventDispatcher = getEventDispatcher(mContext, editText)
26
+ editText.customInsertionActionModeCallback = PasteInputActionCallback(editText, disabled, eventDispatcher)
27
+ editText.customSelectionActionModeCallback = PasteInputActionCallback(editText, disabled, eventDispatcher)
28
+ editText.setDisableCopyPaste(disabled)
29
+ }
30
+
31
+ private fun getEventDispatcher(reactContext: ReactContext, editText: ReactEditText): EventDispatcher? {
32
+ return UIManagerHelper.getEventDispatcherForReactTag(reactContext, editText.id)
33
+ }
34
+
35
+ override fun createViewInstance(context: ThemedReactContext): PasteInputEditText {
36
+ val editText = PasteInputEditText(context)
37
+ val inputType = editText.inputType
38
+
39
+ editText.inputType = inputType and (InputType.TYPE_TEXT_FLAG_MULTI_LINE.inv())
40
+ editText.returnKeyType = "done"
41
+ val eventDispatcher = getEventDispatcher(mContext, editText)
42
+ editText.customInsertionActionModeCallback = PasteInputActionCallback(editText, disableCopyPaste, eventDispatcher)
43
+ editText.customSelectionActionModeCallback = PasteInputActionCallback(editText, disableCopyPaste, eventDispatcher)
44
+
45
+ return editText
46
+ }
47
+
48
+ override fun addEventEmitters(reactContext: ThemedReactContext, editText: ReactEditText) {
49
+ super.addEventEmitters(reactContext, editText)
50
+
51
+ val pasteInputEditText = editText as PasteInputEditText
52
+ val eventDispatcher = getEventDispatcher(reactContext, editText)
53
+ pasteInputEditText.setOnPasteListener(PasteInputListener(pasteInputEditText, reactContext.surfaceId), eventDispatcher)
54
+ }
55
+
56
+ override fun getExportedCustomBubblingEventTypeConstants(): MutableMap<String, Any> {
57
+ val map = super.getExportedCustomBubblingEventTypeConstants()?.toMutableMap()
58
+ ?: return mutableMapOf()
59
+
60
+ map["onPaste"] = MapBuilder.of(
61
+ "phasedRegistrationNames",
62
+ MapBuilder.of("bubbled", "onPaste")
63
+ )
64
+
65
+ return map
66
+ }
67
+
68
+ companion object {
69
+ const val NAME = "PasteTextInput"
70
+ const val CACHE_DIR_NAME = "mmPasteInput"
71
+ }
72
+ }
@@ -0,0 +1,14 @@
1
+ package com.mattermost.pasteinputtext
2
+
3
+ import com.facebook.react.ReactPackage
4
+ import com.facebook.react.bridge.NativeModule
5
+ import com.facebook.react.bridge.ReactApplicationContext
6
+ import com.facebook.react.uimanager.ViewManager
7
+
8
+ class PasteTextInputPackage : ReactPackage {
9
+ override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> =
10
+ listOf(PasteTextInputManager(reactContext))
11
+
12
+ override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> =
13
+ emptyList()
14
+ }
@@ -0,0 +1,41 @@
1
+ package com.mattermost.pasteinputtext;
2
+
3
+ import androidx.annotation.NonNull;
4
+ import androidx.annotation.Nullable;
5
+
6
+ import com.facebook.react.bridge.Arguments;
7
+ import com.facebook.react.bridge.ReadableMap;
8
+ import com.facebook.react.bridge.WritableMap;
9
+ import com.facebook.react.uimanager.events.Event;
10
+
11
+ public class PasteTextInputPasteEvent extends Event<PasteTextInputPasteEvent> {
12
+ private static final String EVENT_NAME = "onPaste";
13
+ private final ReadableMap mEventData;
14
+
15
+ @Deprecated
16
+ public PasteTextInputPasteEvent(int viewId) {
17
+ this(-1, viewId, null);
18
+ }
19
+
20
+ public PasteTextInputPasteEvent(int surfaceId, int viewId, ReadableMap eventData) {
21
+ super(surfaceId, viewId);
22
+ mEventData = eventData;
23
+ }
24
+
25
+ public boolean canCoalesce() {
26
+ return false;
27
+ }
28
+
29
+ @NonNull
30
+ public String getEventName() {
31
+ return EVENT_NAME;
32
+ }
33
+
34
+ @Nullable
35
+ protected WritableMap getEventData() {
36
+ WritableMap eventData = Arguments.createMap();
37
+ eventData.putInt("target", this.getViewTag());
38
+ eventData.merge(mEventData);
39
+ return eventData;
40
+ }
41
+ }
@@ -0,0 +1,174 @@
1
+ package com.mattermost.pasteinputtext
2
+
3
+ import android.content.Context
4
+ import android.database.Cursor
5
+ import android.net.Uri
6
+ import android.provider.DocumentsContract
7
+ import android.provider.MediaStore
8
+ import android.provider.OpenableColumns
9
+ import android.util.Log
10
+ import android.text.TextUtils
11
+ import java.io.*
12
+
13
+ object RealPathUtil {
14
+ init {
15
+ deleteTempFiles(File(PasteTextInputManager.CACHE_DIR_NAME))
16
+ }
17
+
18
+ fun getRealPathFromURI(context: Context, uri: Uri): String? {
19
+ // DocumentProvider
20
+ if (DocumentsContract.isDocumentUri(context, uri)) {
21
+ // ExternalStorageProvider
22
+ if (isExternalStorageDocument(uri)) {
23
+ val docId = DocumentsContract.getDocumentId(uri)
24
+ val split = docId.split((":").toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
25
+ val type = split[0]
26
+ if ("primary".equals(type, ignoreCase = true)) {
27
+ return context.getExternalFilesDir(split[1])?.absolutePath
28
+ }
29
+ } else if (isDownloadsDocument(uri)) {
30
+ // DownloadsProvider
31
+ val id = DocumentsContract.getDocumentId(uri)
32
+ if (!TextUtils.isEmpty(id)) {
33
+ if (id.startsWith("raw:")) {
34
+ return id.replaceFirst(("raw:").toRegex(), "")
35
+ }
36
+ try {
37
+ return getPathFromSavingTempFile(context, uri)
38
+ } catch (e: NumberFormatException) {
39
+ Log.e("ReactNative", "DownloadsProvider unexpected uri $uri")
40
+ return null
41
+ }
42
+ }
43
+ } else if (isMediaDocument(uri)) {
44
+ // MediaProvider
45
+ val docId = DocumentsContract.getDocumentId(uri)
46
+ val split = docId.split((":").toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
47
+ val type = split[0]
48
+ var contentUri: Uri? = null
49
+ when (type) {
50
+ "image" -> {
51
+ contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
52
+ }
53
+ "video" -> {
54
+ contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI
55
+ }
56
+ "audio" -> {
57
+ contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
58
+ }
59
+ }
60
+ val selectionArgs = arrayOf(split[1])
61
+ return contentUri?.let { getDataColumn(context, it, selectionArgs) }
62
+ }
63
+ }
64
+ if ("content".equals(uri.scheme, ignoreCase = true)) {
65
+ // MediaStore (and general)
66
+ if (isGooglePhotosUri(uri)) {
67
+ return uri.lastPathSegment
68
+ }
69
+ // Try save to tmp file, and return tmp file path
70
+ return getPathFromSavingTempFile(context, uri)
71
+ } else if ("file".equals(uri.scheme, ignoreCase = true)) {
72
+ return uri.path
73
+ }
74
+ return null
75
+ }
76
+
77
+ private fun getPathFromSavingTempFile(context: Context, uri: Uri): String? {
78
+ val tmpFile: File
79
+ var fileName: String? = null
80
+ // Try and get the filename from the Uri
81
+ try {
82
+ val returnCursor = context.contentResolver.query(uri, null, null, null, null)
83
+ val nameIndex = returnCursor?.getColumnIndex(OpenableColumns.DISPLAY_NAME)
84
+ returnCursor?.moveToFirst()
85
+ fileName = sanitizeFilename(nameIndex?.let { returnCursor.getString(it) })
86
+ returnCursor?.close()
87
+ } catch (e: Exception) {
88
+ // just continue to get the filename with the last segment of the path
89
+ }
90
+ try {
91
+ if (fileName == null) {
92
+ fileName = sanitizeFilename(uri.lastPathSegment.toString().trim())
93
+ }
94
+ val cacheDir = File(context.cacheDir, PasteTextInputManager.CACHE_DIR_NAME)
95
+ if (!cacheDir.exists()) {
96
+ cacheDir.mkdirs()
97
+ }
98
+
99
+ tmpFile = fileName?.let { File(cacheDir, it) }!!
100
+ tmpFile.createNewFile()
101
+ val pfd = context.contentResolver.openFileDescriptor(uri, "r")
102
+ val src = FileInputStream(pfd?.fileDescriptor).channel
103
+ val dst = FileOutputStream(tmpFile).channel
104
+ dst.transferFrom(src, 0, src.size())
105
+ src.close()
106
+ dst.close()
107
+ pfd?.close()
108
+ } catch (ex: IOException) {
109
+ return null
110
+ }
111
+ return tmpFile.absolutePath
112
+ }
113
+
114
+ private fun sanitizeFilename(filename: String?): String? {
115
+ if (filename == null) {
116
+ return null
117
+ }
118
+
119
+ val f = File(filename)
120
+ return f.name
121
+ }
122
+
123
+ private fun getDataColumn(context: Context, uri: Uri,
124
+ selectionArgs: Array<String>): String? {
125
+ var cursor: Cursor? = null
126
+ val column = "_data"
127
+ val selection = "_id=?"
128
+ val projection = arrayOf(column)
129
+ try {
130
+ cursor = context.contentResolver.query(uri, projection, selection, selectionArgs, null)
131
+ if (cursor != null && cursor.moveToFirst()) {
132
+ val index = cursor.getColumnIndexOrThrow(column)
133
+ return cursor.getString(index)
134
+ }
135
+ } finally {
136
+ cursor?.close()
137
+ }
138
+
139
+ return null
140
+ }
141
+
142
+ private fun isExternalStorageDocument(uri: Uri): Boolean {
143
+ return "com.android.externalstorage.documents" == uri.authority
144
+ }
145
+
146
+ private fun isDownloadsDocument(uri: Uri): Boolean {
147
+ return "com.android.providers.downloads.documents" == uri.authority
148
+ }
149
+
150
+ private fun isMediaDocument(uri: Uri): Boolean {
151
+ return "com.android.providers.media.documents" == uri.authority
152
+ }
153
+
154
+ private fun isGooglePhotosUri(uri: Uri): Boolean {
155
+ return "com.google.android.apps.photos.content" == uri.authority
156
+ }
157
+
158
+ private fun deleteTempFiles(dir: File) {
159
+ try {
160
+ if (dir.isDirectory) {
161
+ deleteRecursive(dir)
162
+ }
163
+ } catch (e: Exception) {
164
+ // do nothing
165
+ }
166
+ }
167
+
168
+ private fun deleteRecursive(fileOrDirectory: File) {
169
+ if (fileOrDirectory.isDirectory)
170
+ for (child in fileOrDirectory.listFiles()!!)
171
+ deleteRecursive(child)
172
+ fileOrDirectory.delete()
173
+ }
174
+ }
@@ -0,0 +1,20 @@
1
+ //
2
+ // NSData+MimeType.h
3
+ // Mattermost
4
+ //
5
+ // Created by Tek Min Ewe on 04/08/2019.
6
+ // Copyright © 2019 Facebook. All rights reserved.
7
+ //
8
+
9
+ #import <Foundation/Foundation.h>
10
+
11
+ NS_ASSUME_NONNULL_BEGIN
12
+
13
+ @interface NSData (MimeType)
14
+
15
+ -(NSString *)mimeType;
16
+ -(NSString *)extension;
17
+
18
+ @end
19
+
20
+ NS_ASSUME_NONNULL_END
@@ -0,0 +1,59 @@
1
+ //
2
+ // NSData+MimeType.m
3
+ // Mattermost
4
+ //
5
+ // Created by Tek Min Ewe on 04/08/2019.
6
+ // Copyright © 2019 Facebook. All rights reserved.
7
+ //
8
+
9
+ #import "NSData+MimeType.h"
10
+
11
+ @implementation NSData (MimeType)
12
+
13
+ -(NSString *)mimeType {
14
+ uint8_t c;
15
+ [self getBytes:&c length:1];
16
+
17
+ switch (c) {
18
+ case 0xFF:
19
+ return @"image/jpeg";
20
+ break;
21
+ case 0x89:
22
+ return @"image/png";
23
+ break;
24
+ case 0x47:
25
+ return @"image/gif";
26
+ break;
27
+ case 0x49:
28
+ case 0x4D:
29
+ return @"image/tiff";
30
+ break;
31
+ default:
32
+ return @"";
33
+ }
34
+ }
35
+
36
+ -(NSString *)extension {
37
+ uint8_t c;
38
+ [self getBytes:&c length:1];
39
+
40
+ switch (c) {
41
+ case 0xFF:
42
+ return @"jpg";
43
+ break;
44
+ case 0x89:
45
+ return @"png";
46
+ break;
47
+ case 0x47:
48
+ return @"gif";
49
+ break;
50
+ case 0x49:
51
+ case 0x4D:
52
+ return @"tiff";
53
+ break;
54
+ default:
55
+ return @"";
56
+ }
57
+ }
58
+
59
+ @end
@@ -0,0 +1 @@
1
+