react-native-my-uploader-android 1.0.21 → 1.0.22

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.
@@ -1,173 +1,173 @@
1
- package com.myuploader
2
-
3
- import android.app.Activity
4
- import android.content.Intent
5
- import android.net.Uri
6
- import android.provider.OpenableColumns
7
- import android.util.Base64
8
- import com.facebook.react.bridge.*
9
- import java.io.ByteArrayOutputStream
10
- import java.net.URLConnection
11
-
12
- class MyUploaderModule(private val reactContext: ReactApplicationContext) :
13
- ReactContextBaseJavaModule(reactContext), ActivityEventListener {
14
-
15
- private var pickerPromise: Promise? = null
16
- private var maxSize: Double = 0.0
17
- private var maxFiles: Int = 0
18
- private var excludedUris: List<String> = emptyList()
19
-
20
- init {
21
- reactContext.addActivityEventListener(this)
22
- }
23
-
24
- override fun getName(): String = "DocumentPicker"
25
-
26
- companion object {
27
- private const val REQUEST_CODE = 9900
28
- private const val E_ACTIVITY_DOES_NOT_EXIST = "E_ACTIVITY_DOES_NOT_EXIST"
29
- private const val E_PICKER_CANCELLED = "E_PICKER_CANCELLED"
30
- private const val E_FAILED_TO_OPEN_DOCUMENT = "E_FAILED_TO_OPEN_DOCUMENT"
31
- private const val E_FILE_TOO_LARGE = "E_FILE_TOO_LARGE"
32
- private const val E_MAX_FILES_EXCEEDED = "E_MAX_FILES_EXCEEDED"
33
- private const val E_INVALID_OPTIONS = "E_INVALID_OPTIONS"
34
- }
35
-
36
- @ReactMethod
37
- fun openDocument(options: ReadableMap, promise: Promise) {
38
- if (pickerPromise != null) {
39
- promise.reject(E_FAILED_TO_OPEN_DOCUMENT, "Başka bir dosya seçme işlemi zaten devam ediyor.")
40
- return
41
- }
42
-
43
- this.pickerPromise = promise
44
-
45
- val multipleFiles = options.takeIf { it.hasKey("multipleFiles") }?.getBoolean("multipleFiles") ?: false
46
- val jsMaxFiles = options.takeIf { it.hasKey("maxFiles") }?.getInt("maxFiles") ?: 0
47
-
48
- // KURAL KONTROLÜ (NATIVE): JS tarafındaki kontrolü burada da yaparak güvenliği artır.
49
- if (!multipleFiles && jsMaxFiles > 1) {
50
- promise.reject(E_INVALID_OPTIONS, "`maxFiles` değeri, `multipleFiles` false iken 1'den büyük olamaz.")
51
- return
52
- }
53
-
54
- // KURAL UYGULAMA (NATIVE): `maxFiles` için nihai değeri hesapla.
55
- val effectiveMaxFiles = when {
56
- multipleFiles && jsMaxFiles == 0 -> 3 // Varsayılan: 3
57
- !multipleFiles -> 1 // Tekli seçimde her zaman 1
58
- else -> jsMaxFiles // Belirtilen değeri kullan
59
- }
60
-
61
- // Değerleri sınıf değişkenlerine ata
62
- this.maxFiles = effectiveMaxFiles
63
- this.maxSize = options.takeIf { it.hasKey("maxSize") }?.getDouble("maxSize") ?: 0.0
64
- this.excludedUris = options.takeIf { it.hasKey("excludedUris") }
65
- ?.getArray("excludedUris")?.toArrayList()?.mapNotNull { it.toString() } ?: emptyList()
66
-
67
- val currentActivity = reactContext.currentActivity
68
- if (currentActivity == null) {
69
- pickerPromise?.reject(E_ACTIVITY_DOES_NOT_EXIST, "Activity mevcut değil.")
70
- pickerPromise = null
71
- return
72
- }
73
-
74
- val fileTypes = options.takeIf { it.hasKey("fileTypes") }
75
- ?.getArray("fileTypes")?.toArrayList()?.mapNotNull { it.toString() } ?: listOf("*/*")
76
- val mimeTypes = if (fileTypes.isEmpty()) arrayOf("*/*") else fileTypes.toTypedArray()
77
-
78
- try {
79
- // ANAHTAR: ACTION_GET_CONTENT, güvenilir çoklu seçimi etkinleştirir.
80
- val intent = Intent(Intent.ACTION_GET_CONTENT).apply {
81
- type = "*/*"
82
- addCategory(Intent.CATEGORY_OPENABLE)
83
- putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes)
84
-
85
- if (multipleFiles) {
86
- putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
87
- }
88
- }
89
- currentActivity.startActivityForResult(Intent.createChooser(intent, "Dosya Seçin"), REQUEST_CODE)
90
- } catch (e: Exception) {
91
- pickerPromise?.reject(E_FAILED_TO_OPEN_DOCUMENT, e)
92
- pickerPromise = null
93
- }
94
- }
95
-
96
- override fun onActivityResult(activity: Activity, requestCode: Int, resultCode: Int, data: Intent?) {
97
- if (requestCode != REQUEST_CODE || pickerPromise == null) { return }
98
-
99
- if (resultCode == Activity.RESULT_OK && data != null) {
100
- val allSelectedUris = mutableListOf<Uri>()
101
- data.clipData?.let { clip ->
102
- for (i in 0 until clip.itemCount) {
103
- allSelectedUris.add(clip.getItemAt(i).uri)
104
- }
105
- } ?: data.data?.let { uri ->
106
- allSelectedUris.add(uri)
107
- }
108
-
109
- val newSelectedUris = allSelectedUris.filter { uri -> !excludedUris.contains(uri.toString()) }
110
-
111
- if (this.maxFiles > 0 && newSelectedUris.size > this.maxFiles) {
112
- pickerPromise?.reject(E_MAX_FILES_EXCEEDED, "En fazla ${this.maxFiles} adet yeni dosya seçebilirsiniz.")
113
- pickerPromise = null
114
- return
115
- }
116
-
117
- try {
118
- val fileInfoArray = processSelectedFiles(newSelectedUris)
119
- pickerPromise?.resolve(fileInfoArray)
120
- } catch (e: Exception) {
121
- pickerPromise?.reject(E_FILE_TOO_LARGE, e.message)
122
- }
123
- } else {
124
- pickerPromise?.reject(E_PICKER_CANCELLED, "Dosya seçimi iptal edildi.")
125
- }
126
- pickerPromise = null
127
- }
128
-
129
- override fun onNewIntent(intent: Intent) {}
130
-
131
- private fun processSelectedFiles(uris: List<Uri>): WritableArray {
132
- val fileObjects = WritableNativeArray()
133
- val maxSizeBytes = (maxSize * 1024 * 1024).toLong()
134
-
135
- for (uri in uris) {
136
- reactContext.contentResolver.query(uri, null, null, null, null)?.use { cursor ->
137
- if (cursor.moveToFirst()) {
138
- val fileNameIndex = cursor.getColumnIndexOrThrow(OpenableColumns.DISPLAY_NAME)
139
- val fileSizeIndex = cursor.getColumnIndexOrThrow(OpenableColumns.SIZE)
140
- val fileName = cursor.getString(fileNameIndex)
141
- val fileSize = cursor.getLong(fileSizeIndex)
142
-
143
- if (maxSizeBytes > 0 && fileSize > maxSizeBytes) {
144
- throw Exception("Seçilen dosya ($fileName) belirtilen ${maxSize}MB boyutundan büyük.")
145
- }
146
-
147
- val mimeType = getMimeType(fileName)
148
- val base64 = reactContext.contentResolver.openInputStream(uri)?.use { inputStream ->
149
- val byteBuffer = ByteArrayOutputStream()
150
- val buffer = ByteArray(1024)
151
- var len: Int
152
- while (inputStream.read(buffer).also { len = it } != -1) {
153
- byteBuffer.write(buffer, 0, len)
154
- }
155
- Base64.encodeToString(byteBuffer.toByteArray(), Base64.NO_WRAP)
156
- }
157
-
158
- val fileMap = WritableNativeMap().apply {
159
- putString("fileName", fileName)
160
- putDouble("fileSize", fileSize.toDouble())
161
- putString("fileType", mimeType)
162
- putString("fileUri", uri.toString())
163
- putString("base64", base64)
164
- }
165
- fileObjects.pushMap(fileMap)
166
- }
167
- }
168
- }
169
- return fileObjects
170
- }
171
-
172
- private fun getMimeType(fileName: String): String? = URLConnection.guessContentTypeFromName(fileName)
1
+ package com.myuploader
2
+
3
+ import android.app.Activity
4
+ import android.content.Intent
5
+ import android.net.Uri
6
+ import android.provider.OpenableColumns
7
+ import android.util.Base64
8
+ import com.facebook.react.bridge.*
9
+ import java.io.ByteArrayOutputStream
10
+ import java.net.URLConnection
11
+
12
+ class MyUploaderModule(private val reactContext: ReactApplicationContext) :
13
+ ReactContextBaseJavaModule(reactContext), ActivityEventListener {
14
+
15
+ private var pickerPromise: Promise? = null
16
+ private var maxSize: Double = 0.0
17
+ private var maxFiles: Int = 0
18
+ private var excludedUris: List<String> = emptyList()
19
+
20
+ init {
21
+ reactContext.addActivityEventListener(this)
22
+ }
23
+
24
+ override fun getName(): String = "DocumentPicker"
25
+
26
+ companion object {
27
+ private const val REQUEST_CODE = 9900
28
+ private const val E_ACTIVITY_DOES_NOT_EXIST = "E_ACTIVITY_DOES_NOT_EXIST"
29
+ private const val E_PICKER_CANCELLED = "E_PICKER_CANCELLED"
30
+ private const val E_FAILED_TO_OPEN_DOCUMENT = "E_FAILED_TO_OPEN_DOCUMENT"
31
+ private const val E_FILE_TOO_LARGE = "E_FILE_TOO_LARGE"
32
+ private const val E_MAX_FILES_EXCEEDED = "E_MAX_FILES_EXCEEDED"
33
+ private const val E_INVALID_OPTIONS = "E_INVALID_OPTIONS"
34
+ }
35
+
36
+ @ReactMethod
37
+ fun openDocument(options: ReadableMap, promise: Promise) {
38
+ if (pickerPromise != null) {
39
+ promise.reject(E_FAILED_TO_OPEN_DOCUMENT, "Başka bir dosya seçme işlemi zaten devam ediyor.")
40
+ return
41
+ }
42
+
43
+ this.pickerPromise = promise
44
+
45
+ val multipleFiles = options.takeIf { it.hasKey("multipleFiles") }?.getBoolean("multipleFiles") ?: false
46
+ val jsMaxFiles = options.takeIf { it.hasKey("maxFiles") }?.getInt("maxFiles") ?: 0
47
+
48
+ // KURAL KONTROLÜ (NATIVE): JS tarafındaki kontrolü burada da yaparak güvenliği artır.
49
+ if (!multipleFiles && jsMaxFiles > 1) {
50
+ promise.reject(E_INVALID_OPTIONS, "`maxFiles` değeri, `multipleFiles` false iken 1'den büyük olamaz.")
51
+ return
52
+ }
53
+
54
+ // KURAL UYGULAMA (NATIVE): `maxFiles` için nihai değeri hesapla.
55
+ val effectiveMaxFiles = when {
56
+ multipleFiles && jsMaxFiles == 0 -> 3 // Varsayılan: 3
57
+ !multipleFiles -> 1 // Tekli seçimde her zaman 1
58
+ else -> jsMaxFiles // Belirtilen değeri kullan
59
+ }
60
+
61
+ // Değerleri sınıf değişkenlerine ata
62
+ this.maxFiles = effectiveMaxFiles
63
+ this.maxSize = options.takeIf { it.hasKey("maxSize") }?.getDouble("maxSize") ?: 0.0
64
+ this.excludedUris = options.takeIf { it.hasKey("excludedUris") }
65
+ ?.getArray("excludedUris")?.toArrayList()?.mapNotNull { it.toString() } ?: emptyList()
66
+
67
+ val currentActivity = reactContext.currentActivity
68
+ if (currentActivity == null) {
69
+ pickerPromise?.reject(E_ACTIVITY_DOES_NOT_EXIST, "Activity mevcut değil.")
70
+ pickerPromise = null
71
+ return
72
+ }
73
+
74
+ val fileTypes = options.takeIf { it.hasKey("fileTypes") }
75
+ ?.getArray("fileTypes")?.toArrayList()?.mapNotNull { it.toString() } ?: listOf("*/*")
76
+ val mimeTypes = if (fileTypes.isEmpty()) arrayOf("*/*") else fileTypes.toTypedArray()
77
+
78
+ try {
79
+ // ANAHTAR: ACTION_GET_CONTENT, güvenilir çoklu seçimi etkinleştirir.
80
+ val intent = Intent(Intent.ACTION_GET_CONTENT).apply {
81
+ type = "*/*"
82
+ addCategory(Intent.CATEGORY_OPENABLE)
83
+ putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes)
84
+
85
+ if (multipleFiles) {
86
+ putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
87
+ }
88
+ }
89
+ currentActivity.startActivityForResult(Intent.createChooser(intent, "Dosya Seçin"), REQUEST_CODE)
90
+ } catch (e: Exception) {
91
+ pickerPromise?.reject(E_FAILED_TO_OPEN_DOCUMENT, e)
92
+ pickerPromise = null
93
+ }
94
+ }
95
+
96
+ override fun onActivityResult(activity: Activity, requestCode: Int, resultCode: Int, data: Intent?) {
97
+ if (requestCode != REQUEST_CODE || pickerPromise == null) { return }
98
+
99
+ if (resultCode == Activity.RESULT_OK && data != null) {
100
+ val allSelectedUris = mutableListOf<Uri>()
101
+ data.clipData?.let { clip ->
102
+ for (i in 0 until clip.itemCount) {
103
+ allSelectedUris.add(clip.getItemAt(i).uri)
104
+ }
105
+ } ?: data.data?.let { uri ->
106
+ allSelectedUris.add(uri)
107
+ }
108
+
109
+ val newSelectedUris = allSelectedUris.filter { uri -> !excludedUris.contains(uri.toString()) }
110
+
111
+ if (this.maxFiles > 0 && newSelectedUris.size > this.maxFiles) {
112
+ pickerPromise?.reject(E_MAX_FILES_EXCEEDED, "En fazla ${this.maxFiles} adet yeni dosya seçebilirsiniz.")
113
+ pickerPromise = null
114
+ return
115
+ }
116
+
117
+ try {
118
+ val fileInfoArray = processSelectedFiles(newSelectedUris)
119
+ pickerPromise?.resolve(fileInfoArray)
120
+ } catch (e: Exception) {
121
+ pickerPromise?.reject(E_FILE_TOO_LARGE, e.message)
122
+ }
123
+ } else {
124
+ pickerPromise?.reject(E_PICKER_CANCELLED, "Dosya seçimi iptal edildi.")
125
+ }
126
+ pickerPromise = null
127
+ }
128
+
129
+ override fun onNewIntent(intent: Intent) {}
130
+
131
+ private fun processSelectedFiles(uris: List<Uri>): WritableArray {
132
+ val fileObjects = WritableNativeArray()
133
+ val maxSizeBytes = (maxSize * 1024 * 1024).toLong()
134
+
135
+ for (uri in uris) {
136
+ reactContext.contentResolver.query(uri, null, null, null, null)?.use { cursor ->
137
+ if (cursor.moveToFirst()) {
138
+ val fileNameIndex = cursor.getColumnIndexOrThrow(OpenableColumns.DISPLAY_NAME)
139
+ val fileSizeIndex = cursor.getColumnIndexOrThrow(OpenableColumns.SIZE)
140
+ val fileName = cursor.getString(fileNameIndex)
141
+ val fileSize = cursor.getLong(fileSizeIndex)
142
+
143
+ if (maxSizeBytes > 0 && fileSize > maxSizeBytes) {
144
+ throw Exception("Seçilen dosya ($fileName) belirtilen ${maxSize}MB boyutundan büyük.")
145
+ }
146
+
147
+ val mimeType = getMimeType(fileName)
148
+ val base64 = reactContext.contentResolver.openInputStream(uri)?.use { inputStream ->
149
+ val byteBuffer = ByteArrayOutputStream()
150
+ val buffer = ByteArray(1024)
151
+ var len: Int
152
+ while (inputStream.read(buffer).also { len = it } != -1) {
153
+ byteBuffer.write(buffer, 0, len)
154
+ }
155
+ Base64.encodeToString(byteBuffer.toByteArray(), Base64.NO_WRAP)
156
+ }
157
+
158
+ val fileMap = WritableNativeMap().apply {
159
+ putString("fileName", fileName)
160
+ putDouble("fileSize", fileSize.toDouble())
161
+ putString("fileType", mimeType)
162
+ putString("fileUri", uri.toString())
163
+ putString("base64", base64)
164
+ }
165
+ fileObjects.pushMap(fileMap)
166
+ }
167
+ }
168
+ }
169
+ return fileObjects
170
+ }
171
+
172
+ private fun getMimeType(fileName: String): String? = URLConnection.guessContentTypeFromName(fileName)
173
173
  }
@@ -1,16 +1,16 @@
1
- package com.myuploader
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 MyUploaderPackage : ReactPackage {
9
- override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
10
- return listOf(MyUploaderModule(reactContext))
11
- }
12
-
13
- override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
14
- return emptyList()
15
- }
1
+ package com.myuploader
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 MyUploaderPackage : ReactPackage {
9
+ override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
10
+ return listOf(MyUploaderModule(reactContext))
11
+ }
12
+
13
+ override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
14
+ return emptyList()
15
+ }
16
16
  }
package/ios/MyUploader.h CHANGED
@@ -1,8 +1,8 @@
1
-
2
- #ifndef MuhasebeonayMain_Bridging_Header_h
3
- #define MuhasebeonayMain_Bridging_Header_h
4
- #import "React/RCTBridgeModule.h"
5
- #import "React/RCTViewManager.h"
6
- #import "React/RCTEventEmitter.h"
7
-
8
-
1
+
2
+ #ifndef MuhasebeonayMain_Bridging_Header_h
3
+ #define MuhasebeonayMain_Bridging_Header_h
4
+ #import "React/RCTBridgeModule.h"
5
+ #import "React/RCTViewManager.h"
6
+ #import "React/RCTEventEmitter.h"
7
+
8
+
package/ios/MyUploader.mm CHANGED
@@ -1,11 +1,11 @@
1
-
2
- #import <Foundation/Foundation.h>
3
- #import <React/RCTBridgeModule.h>
4
-
5
- @interface RCT_EXTERN_MODULE(MyUploader, NSObject)
6
-
7
- RCT_EXTERN_METHOD(openDocument:(NSDictionary)options
8
- successCallback:(RCTResponseSenderBlock)successCallback
9
- failureCallback:(RCTResponseSenderBlock)failureCallback)
10
-
1
+
2
+ #import <Foundation/Foundation.h>
3
+ #import <React/RCTBridgeModule.h>
4
+
5
+ @interface RCT_EXTERN_MODULE(MyUploader, NSObject)
6
+
7
+ RCT_EXTERN_METHOD(openDocument:(NSDictionary)options
8
+ successCallback:(RCTResponseSenderBlock)successCallback
9
+ failureCallback:(RCTResponseSenderBlock)failureCallback)
10
+
11
11
  @end
@@ -1,98 +1,98 @@
1
- import Foundation
2
- import MobileCoreServices
3
- import UIKit
4
- import UniformTypeIdentifiers
5
- import React
6
-
7
- @objc(MyUploader)
8
- class MyUploader: NSObject, UIDocumentPickerDelegate {
9
-
10
- private var resolveCallback: RCTResponseSenderBlock?
11
- private var rejectCallback: RCTResponseSenderBlock?
12
- private var maxFileSize: Int64 = 3 * 1024 * 1024 // 3 MB
13
- private var currentPicker: UIDocumentPickerViewController?
14
-
15
- @objc static func requiresMainQueueSetup() -> Bool {
16
- return true
17
- }
18
-
19
- @objc(openDocument:successCallback:failureCallback:)
20
- func openDocument(_ options: NSDictionary,
21
- successCallback: @escaping RCTResponseSenderBlock,
22
- failureCallback: @escaping RCTResponseSenderBlock) {
23
-
24
- self.resolveCallback = successCallback
25
- self.rejectCallback = failureCallback
26
-
27
- let multipleFiles = options["multipleFiles"] as? Bool ?? false
28
- let fileTypes = options["fileTypes"] as? [String] ?? ["public.data"]
29
-
30
- let supportedTypes: [UTType] = fileTypes.compactMap { mime in
31
- switch mime {
32
- case "application/pdf": return .pdf
33
- case "image/*": return .image
34
- case "application/msword": return UTType(importedAs: "com.microsoft.word.doc")
35
- case "application/vnd.openxmlformats-officedocument.wordprocessingml.document": return UTType(importedAs: "org.openxmlformats.wordprocessingml.document")
36
- case "application/vnd.ms-excel": return UTType(importedAs: "com.microsoft.excel.xls")
37
- case "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": return UTType(importedAs: "org.openxmlformats.spreadsheetml.sheet")
38
- case "application/vnd.ms-powerpoint": return UTType(importedAs: "com.microsoft.powerpoint.ppt")
39
- case "application/vnd.openxmlformats-officedocument.presentationml.presentation": return UTType(importedAs: "org.openxmlformats.presentationml.presentation")
40
- default: return nil
41
- }
42
- }
43
-
44
- let picker = UIDocumentPickerViewController(forOpeningContentTypes: supportedTypes, asCopy: true)
45
- picker.allowsMultipleSelection = multipleFiles
46
- picker.delegate = self
47
-
48
- DispatchQueue.main.async {
49
- if let rootVC = UIApplication.shared.windows.first?.rootViewController {
50
- var topVC = rootVC
51
- while let presented = topVC.presentedViewController {
52
- topVC = presented
53
- }
54
- topVC.present(picker, animated: true, completion: nil)
55
- } else {
56
- failureCallback(["{\"code\":\"NO_ROOT\", \"message\":\"Root view controller bulunamadı.\"}"])
57
- }
58
- }
59
- }
60
-
61
- func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
62
- var results: [[String: Any]] = []
63
-
64
- for url in urls {
65
- do {
66
- let fileData = try Data(contentsOf: url)
67
- let fileSize = Int64(fileData.count)
68
-
69
- if fileSize > maxFileSize {
70
- rejectCallback?(["{\"code\":\"TOO_LARGE\", \"message\":\"Seçilen dosya 3 MB'dan büyük olamaz.\"}"])
71
- return
72
- }
73
-
74
- let base64String = fileData.base64EncodedString()
75
- let fileName = url.lastPathComponent
76
- let fileType = url.pathExtension
77
-
78
- let dict: [String: Any] = [
79
- "fileName": fileName,
80
- "fileSize": fileSize,
81
- "fileType": fileType,
82
- "fileUri": url.absoluteString,
83
- "base64": base64String
84
- ]
85
- results.append(dict)
86
- } catch {
87
- rejectCallback?(["{\"code\":\"READ_ERROR\", \"message\":\"Dosya okunamadı: \(error.localizedDescription)\"}"])
88
- return
89
- }
90
- }
91
-
92
- resolveCallback?(results)
93
- }
94
-
95
- func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController) {
96
- rejectCallback?(["{\"code\":\"CANCELLED\", \"message\":\"Kullanıcı iptal etti\"}"])
97
- }
1
+ import Foundation
2
+ import MobileCoreServices
3
+ import UIKit
4
+ import UniformTypeIdentifiers
5
+ import React
6
+
7
+ @objc(MyUploader)
8
+ class MyUploader: NSObject, UIDocumentPickerDelegate {
9
+
10
+ private var resolveCallback: RCTResponseSenderBlock?
11
+ private var rejectCallback: RCTResponseSenderBlock?
12
+ private var maxFileSize: Int64 = 3 * 1024 * 1024 // 3 MB
13
+ private var currentPicker: UIDocumentPickerViewController?
14
+
15
+ @objc static func requiresMainQueueSetup() -> Bool {
16
+ return true
17
+ }
18
+
19
+ @objc(openDocument:successCallback:failureCallback:)
20
+ func openDocument(_ options: NSDictionary,
21
+ successCallback: @escaping RCTResponseSenderBlock,
22
+ failureCallback: @escaping RCTResponseSenderBlock) {
23
+
24
+ self.resolveCallback = successCallback
25
+ self.rejectCallback = failureCallback
26
+
27
+ let multipleFiles = options["multipleFiles"] as? Bool ?? false
28
+ let fileTypes = options["fileTypes"] as? [String] ?? ["public.data"]
29
+
30
+ let supportedTypes: [UTType] = fileTypes.compactMap { mime in
31
+ switch mime {
32
+ case "application/pdf": return .pdf
33
+ case "image/*": return .image
34
+ case "application/msword": return UTType(importedAs: "com.microsoft.word.doc")
35
+ case "application/vnd.openxmlformats-officedocument.wordprocessingml.document": return UTType(importedAs: "org.openxmlformats.wordprocessingml.document")
36
+ case "application/vnd.ms-excel": return UTType(importedAs: "com.microsoft.excel.xls")
37
+ case "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": return UTType(importedAs: "org.openxmlformats.spreadsheetml.sheet")
38
+ case "application/vnd.ms-powerpoint": return UTType(importedAs: "com.microsoft.powerpoint.ppt")
39
+ case "application/vnd.openxmlformats-officedocument.presentationml.presentation": return UTType(importedAs: "org.openxmlformats.presentationml.presentation")
40
+ default: return nil
41
+ }
42
+ }
43
+
44
+ let picker = UIDocumentPickerViewController(forOpeningContentTypes: supportedTypes, asCopy: true)
45
+ picker.allowsMultipleSelection = multipleFiles
46
+ picker.delegate = self
47
+
48
+ DispatchQueue.main.async {
49
+ if let rootVC = UIApplication.shared.windows.first?.rootViewController {
50
+ var topVC = rootVC
51
+ while let presented = topVC.presentedViewController {
52
+ topVC = presented
53
+ }
54
+ topVC.present(picker, animated: true, completion: nil)
55
+ } else {
56
+ failureCallback(["{\"code\":\"NO_ROOT\", \"message\":\"Root view controller bulunamadı.\"}"])
57
+ }
58
+ }
59
+ }
60
+
61
+ func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
62
+ var results: [[String: Any]] = []
63
+
64
+ for url in urls {
65
+ do {
66
+ let fileData = try Data(contentsOf: url)
67
+ let fileSize = Int64(fileData.count)
68
+
69
+ if fileSize > maxFileSize {
70
+ rejectCallback?(["{\"code\":\"TOO_LARGE\", \"message\":\"Seçilen dosya 3 MB'dan büyük olamaz.\"}"])
71
+ return
72
+ }
73
+
74
+ let base64String = fileData.base64EncodedString()
75
+ let fileName = url.lastPathComponent
76
+ let fileType = url.pathExtension
77
+
78
+ let dict: [String: Any] = [
79
+ "fileName": fileName,
80
+ "fileSize": fileSize,
81
+ "fileType": fileType,
82
+ "fileUri": url.absoluteString,
83
+ "base64": base64String
84
+ ]
85
+ results.append(dict)
86
+ } catch {
87
+ rejectCallback?(["{\"code\":\"READ_ERROR\", \"message\":\"Dosya okunamadı: \(error.localizedDescription)\"}"])
88
+ return
89
+ }
90
+ }
91
+
92
+ resolveCallback?(results)
93
+ }
94
+
95
+ func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController) {
96
+ rejectCallback?(["{\"code\":\"CANCELLED\", \"message\":\"Kullanıcı iptal etti\"}"])
97
+ }
98
98
  }
@@ -5,8 +5,6 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.default = void 0;
7
7
  var _reactNative = require("react-native");
8
- // Native modülün tip tanımı
9
-
10
8
  const LINKING_ERROR = `The package 'react--native-my-uploader' doesn't seem to be linked. Make sure: \n\n` + '- You rebuilt the app after installing the package\n' + '- You are not using Expo Go\n';
11
9
  const DocumentPicker = _reactNative.NativeModules.DocumentPicker ? _reactNative.NativeModules.DocumentPicker : new Proxy({}, {
12
10
  get() {
@@ -1 +1 @@
1
- {"version":3,"names":["_reactNative","require","LINKING_ERROR","DocumentPicker","NativeModules","Proxy","get","Error","_default","exports","default"],"sources":["NativeMyUploader.ts"],"sourcesContent":["import { NativeModules } from 'react-native';\nimport type { FileInfo, DocumentPickerOptions } from './types';\n\n\n// Native modülün tip tanımı\ninterface MyUploaderType {\n openDocument(options: DocumentPickerOptions): Promise<FileInfo[]>;\n}\n\nconst LINKING_ERROR =\n `The package 'react--native-my-uploader' doesn't seem to be linked. Make sure: \\n\\n` +\n '- You rebuilt the app after installing the package\\n' +\n '- You are not using Expo Go\\n';\n \n\nconst DocumentPicker = NativeModules.DocumentPicker\n ? (NativeModules.DocumentPicker as MyUploaderType)\n : new Proxy(\n {},\n {\n get() {\n throw new Error(LINKING_ERROR);\n },\n }\n );\n\nexport default DocumentPicker;"],"mappings":";;;;;;AAAA,IAAAA,YAAA,GAAAC,OAAA;AAIA;;AAKA,MAAMC,aAAa,GACjB,oFAAoF,GACpF,sDAAsD,GACtD,+BAA+B;AAGjC,MAAMC,cAAc,GAAGC,0BAAa,CAACD,cAAc,GAC9CC,0BAAa,CAACD,cAAc,GAC7B,IAAIE,KAAK,CACP,CAAC,CAAC,EACF;EACEC,GAAGA,CAAA,EAAG;IACJ,MAAM,IAAIC,KAAK,CAACL,aAAa,CAAC;EAChC;AACF,CACF,CAAC;AAAC,IAAAM,QAAA,GAAAC,OAAA,CAAAC,OAAA,GAESP,cAAc","ignoreList":[]}
1
+ {"version":3,"names":["_reactNative","require","LINKING_ERROR","DocumentPicker","NativeModules","Proxy","get","Error","_default","exports","default"],"sources":["NativeMyUploader.ts"],"sourcesContent":["import { NativeModules } from 'react-native';\r\nimport type { FileInfo, DocumentPickerOptions } from './types';\r\n\r\ninterface MyUploaderType {\r\n openDocument(options: DocumentPickerOptions): Promise<FileInfo[]>;\r\n}\r\n\r\nconst LINKING_ERROR =\r\n `The package 'react--native-my-uploader' doesn't seem to be linked. Make sure: \\n\\n` +\r\n '- You rebuilt the app after installing the package\\n' +\r\n '- You are not using Expo Go\\n';\r\n \r\n\r\nconst DocumentPicker = NativeModules.DocumentPicker\r\n ? (NativeModules.DocumentPicker as MyUploaderType)\r\n : new Proxy(\r\n {},\r\n {\r\n get() {\r\n throw new Error(LINKING_ERROR);\r\n },\r\n }\r\n );\r\n\r\nexport default DocumentPicker;"],"mappings":";;;;;;AAAA,IAAAA,YAAA,GAAAC,OAAA;AAOA,MAAMC,aAAa,GACjB,oFAAoF,GACpF,sDAAsD,GACtD,+BAA+B;AAGjC,MAAMC,cAAc,GAAGC,0BAAa,CAACD,cAAc,GAC9CC,0BAAa,CAACD,cAAc,GAC7B,IAAIE,KAAK,CACP,CAAC,CAAC,EACF;EACEC,GAAGA,CAAA,EAAG;IACJ,MAAM,IAAIC,KAAK,CAACL,aAAa,CAAC;EAChC;AACF,CACF,CAAC;AAAC,IAAAM,QAAA,GAAAC,OAAA,CAAAC,OAAA,GAESP,cAAc","ignoreList":[]}
@@ -1 +1 @@
1
- {"version":3,"names":[],"sources":["index.d.ts"],"sourcesContent":["// Dosya: index.d.ts\n\n// ADIM 1: Tipleri DIŞA AKTARARAK (export) doğrudan burada tanımla.\n// (Artık 'import' kullanmıyoruz)\n\n/**\n * Native modülden dönen tek bir dosyanın yapısını tanımlar.\n * Bu tip, paket kullanıcıları tarafından import edilebilir.\n */\nexport interface FileInfo {\n fileName: string;\n fileSize: number; // in bytes\n fileType: string | null;\n fileUri: string;\n base64: string;\n}\n\n/**\n * `pickFile` fonksiyonuna gönderilebilecek tüm opsiyonları tanımlar.\n * Bu tip, paket kullanıcıları tarafından import edilebilir.\n */\nexport interface DocumentPickerOptions {\n /**\n * Birden fazla dosya seçimine izin ver.\n * @default false\n */\n multipleFiles?: boolean;\n\n /**\n * Filtrelenecek dosya tipleri (MIME types).\n * @default ['* / *']\n */\n fileTypes?: string[];\n\n /**\n * MB cinsinden maksimum dosya boyutu.\n * @default 0 (limitsiz)\n */\n maxSize?: number;\n\n /**\n * Seçilebilecek maksimum dosya sayısı. `multipleFiles: true` olmalıdır.\n * Belirtilmezse ve `multipleFiles: true` ise varsayılan olarak 3'tür.\n */\n maxFiles?: number;\n\n /**\n * Zaten seçilmiş olduğu için tekrar seçilmesi engellenecek dosyaların URI listesi.\n */\n excludedUris?: string[];\n}\n\n// ADIM 2: Fonksiyonu da DIŞA AKTARARAK (export) tanımla.\n\n/**\n * Dosya seçiciyi açar ve seçilen dosyaların bilgilerini döndürür.\n * @param options Dosya seçici için yapılandırma ayarları.\n * @returns Seçilen dosya bilgilerini içeren bir Promise<FileInfo[]> döner.\n */\nexport function pickFile(options?: DocumentPickerOptions): Promise<FileInfo[]>;"],"mappings":"","ignoreList":[]}
1
+ {"version":3,"names":[],"sources":["index.d.ts"],"sourcesContent":["import * as React from 'react';\r\nimport type {FileInfo,DocumentPickerOptions, MyUploaderProps} from './types';\r\n\r\ndeclare const MyUploader: React.FC<MyUploaderProps>;\r\nexport default MyUploader;\r\n\r\n// Fonksiyonu hala export etmek isterseniz\r\nexport function pickFile(options?: DocumentPickerOptions): Promise<FileInfo[]>;"],"mappings":"","ignoreList":[]}