react-native-my-uploader-android 1.0.32 → 1.0.38

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,177 +1,201 @@
1
1
  package com.myuploaderandroid
2
-
3
- import android.app.DownloadManager
4
- import android.content.BroadcastReceiver
5
- import android.content.Context
6
- import android.content.Intent
7
- import android.content.IntentFilter
8
- import android.net.Uri
2
+ import android.content.ContentValues
9
3
  import android.os.Build
10
4
  import android.os.Environment
11
- import android.util.Log
12
- import android.webkit.CookieManager
13
- import android.webkit.URLUtil
5
+ import android.provider.MediaStore
6
+ import android.webkit.MimeTypeMap
14
7
  import com.facebook.react.bridge.*
8
+ import java.io.BufferedInputStream
15
9
  import java.io.File
10
+ import java.io.FileOutputStream
11
+ import java.io.OutputStream
16
12
  import java.net.HttpURLConnection
17
13
  import java.net.URL
18
- import java.util.concurrent.ConcurrentHashMap
19
-
20
- class DownloadFileModule(private val reactContext: ReactApplicationContext) :
21
- ReactContextBaseJavaModule(reactContext) {
22
-
23
- private val TAG = "DownloadFileModule"
24
- private val downloadPromises = ConcurrentHashMap<Long, Promise>()
25
-
26
- private val receiver: BroadcastReceiver = object : BroadcastReceiver() {
27
- override fun onReceive(context: Context, intent: Intent) {
28
- val downloadId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1)
29
- if (downloadId != -1L) {
30
- downloadPromises.remove(downloadId)?.let { promise ->
31
- checkDownloadStatus(downloadId, promise)
32
- }
14
+ import java.net.URLDecoder
15
+ import java.util.Locale
16
+ class DownloadFileModule ( reactContext: ReactApplicationContext ) : ReactContextBaseJavaModule(reactContext) {
17
+
18
+ override fun getName(): String = "DownloadFileModule"
19
+
20
+ @ReactMethod
21
+ fun downloadFile(urlStr: String, options: ReadableMap, promise: Promise) {
22
+ Thread {
23
+ var connection: HttpURLConnection? = null
24
+ var inputStream: BufferedInputStream? = null
25
+ var outputStream: OutputStream? = null
26
+ var finished = false
27
+
28
+ fun rejectOnce(code: String, message: String) {
29
+ if (!finished) {
30
+ finished = true
31
+ promise.reject(code, message)
33
32
  }
34
33
  }
35
- }
36
-
37
- override fun getName(): String = "DownloadFile"
38
34
 
39
- init {
40
- val intentFilter = IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE)
41
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
42
- reactContext.registerReceiver(receiver, intentFilter, Context.RECEIVER_NOT_EXPORTED)
43
- } else {
44
- reactContext.registerReceiver(receiver, intentFilter)
35
+ fun resolveOnce(value: String) {
36
+ if (!finished) {
37
+ finished = true
38
+ promise.resolve(value)
39
+ }
45
40
  }
46
- }
47
41
 
48
- override fun onCatalystInstanceDestroy() {
49
42
  try {
50
- reactContext.unregisterReceiver(receiver)
51
- } catch (e: Exception) {
52
- Log.w(TAG, "Receiver unregister warning: ${e.message}")
53
- }
54
- super.onCatalystInstanceDestroy()
55
- }
56
-
57
- @ReactMethod
58
- fun downloadFile(fileUrl: String, options: ReadableMap, promise: Promise) {
59
- val isDebug = if (options.hasKey("debug")) options.getBoolean("debug") else false
60
- val maxSizeMB = if (options.hasKey("maxSize")) options.getDouble("maxSize") else 0.0
61
-
62
- // Allowed File Types (Mime Types)
63
- val allowedTypes = if (options.hasKey("fileTypes")) {
64
- options.getArray("fileTypes")?.toArrayList()?.mapNotNull { it.toString() } ?: emptyList()
65
- } else emptyList()
66
-
67
- if (isDebug) Log.d(TAG, "İndirme başlatılıyor: $fileUrl")
43
+ // --- OPTIONS ---
44
+ val maxSizeMB = if (options.hasKey("maxSize")) options.getInt("maxSize") else 0
45
+ val fileTypes = if (options.hasKey("fileTypes")) options.getArray("fileTypes") else null
46
+
47
+ // --- CONNECTION ---
48
+ val url = URL(urlStr)
49
+ connection = url.openConnection() as HttpURLConnection
50
+ connection.requestMethod = "GET"
51
+ connection.connect()
52
+
53
+ // --- HTTP STATUS CHECK ---
54
+ if (connection.responseCode !in 200..299) {
55
+ connection.disconnect()
56
+ rejectOnce(
57
+ "ERR_HTTP",
58
+ "Sunucu hatası: ${connection.responseCode}"
59
+ )
60
+ return@Thread
61
+ }
68
62
 
69
- Thread {
70
- var connection: HttpURLConnection? = null
71
- try {
72
- val url = URL(fileUrl)
73
- connection = url.openConnection() as HttpURLConnection
74
- val cookie = CookieManager.getInstance().getCookie(fileUrl)
75
- if (cookie != null) connection.setRequestProperty("Cookie", cookie)
76
- connection.requestMethod = "HEAD" // Sadece başlıkları çek
77
- connection.connect()
78
-
79
- val responseCode = connection.responseCode
80
- if (responseCode !in 200..299) {
81
- promise.reject("E_HTTP_ERROR", "Sunucu hatası: $responseCode")
63
+ // --- SIZE CHECK ---
64
+ val contentLength = connection.contentLengthLong
65
+ if (maxSizeMB > 0 && contentLength > 0) {
66
+ val maxBytes = maxSizeMB * 1024 * 1024
67
+ if (contentLength > maxBytes) {
68
+ connection.disconnect()
69
+ rejectOnce(
70
+ "ERR_SIZE_LIMIT",
71
+ "Dosya boyutu ($maxSizeMB MB) sınırını aşıyor."
72
+ )
82
73
  return@Thread
83
74
  }
75
+ }
84
76
 
85
- val fileSize = connection.contentLengthLong
86
- val contentType = connection.contentType
87
- val cleanContentType = contentType?.split(";")?.get(0)?.trim() ?: "*/*"
88
-
89
- // 1. Content-Type Kontrolü
90
- if (allowedTypes.isNotEmpty() && !allowedTypes.contains("*/*")) {
91
- var isAllowed = false
92
- for (type in allowedTypes) {
93
- if (type == "*/*" || cleanContentType.equals(type, ignoreCase = true) || cleanContentType.startsWith(type.replace("*", ""))) {
94
- isAllowed = true
95
- break
96
- }
77
+ // --- TYPE CHECK ---
78
+ val contentType = connection.contentType ?: ""
79
+
80
+ if (fileTypes != null && fileTypes.size() > 0) {
81
+ val allowedTypes = HashSet<String>()
82
+ for (i in 0 until fileTypes.size()) {
83
+ val type = fileTypes.getString(i)
84
+ if (type != null) {
85
+ // 🔥 DÜZELTME BURADA: typesList -> allowedTypes yapıldı
86
+ allowedTypes.add(type.lowercase(Locale.ROOT))
97
87
  }
98
- if (!isAllowed) {
99
- promise.reject("E_INVALID_FILE_TYPE", "Dosya türü ($cleanContentType) izin verilenler listesinde yok.")
100
- return@Thread
88
+ }
89
+
90
+ val isAllowed = when {
91
+ allowedTypes.contains("*/*") -> true
92
+ contentType.isEmpty() -> false
93
+ else -> allowedTypes.any {
94
+ contentType.lowercase(Locale.ROOT).contains(it)
101
95
  }
102
96
  }
103
97
 
104
- // 2. Boyut Kontrolü
105
- if (maxSizeMB > 0 && fileSize > 0 && fileSize > maxSizeMB * 1024 * 1024) {
106
- promise.reject("E_FILE_TOO_LARGE", "Dosya boyutu (${(fileSize / 1024.0 / 1024.0).toInt()}MB) limitin (${maxSizeMB}MB) üzerinde.")
98
+ if (!isAllowed) {
99
+ connection.disconnect()
100
+ val displayType = if (contentType.isNotEmpty()) contentType else "Bilinmeyen"
101
+ rejectOnce(
102
+ "ERR_TYPE_MISMATCH",
103
+ "Dosya tipi ($displayType) izin verilenler listesinde yok."
104
+ )
107
105
  return@Thread
108
106
  }
107
+ }
109
108
 
110
- val contentDisposition = connection.getHeaderField("Content-Disposition")
111
- val fileName = URLUtil.guessFileName(fileUrl, contentDisposition, cleanContentType)
109
+ // --- FILE NAME ---
110
+ val fileName = getFileNameFromUrl(urlStr, contentType)
112
111
 
113
- // Dosya Adı Çakışma Önleme
114
- val downloadsDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
115
- val baseName = fileName.substringBeforeLast(".")
116
- val ext = fileName.substringAfterLast(".", "")
117
- var counter = 1
118
- var finalFileName = fileName
119
-
120
- while (File(downloadsDir, finalFileName).exists()) {
121
- finalFileName = if (ext.isNotEmpty()) "$baseName($counter).$ext" else "$baseName($counter)"
122
- counter++
112
+ // --- OPEN STREAM ---
113
+ inputStream = BufferedInputStream(connection.inputStream)
114
+ var finalUri = ""
115
+
116
+ // --- SAVE FILE ---
117
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
118
+ val resolver = reactApplicationContext.contentResolver
119
+ val values = ContentValues().apply {
120
+ put(MediaStore.MediaColumns.DISPLAY_NAME, fileName)
121
+ put(MediaStore.MediaColumns.MIME_TYPE, contentType)
122
+ put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS)
123
123
  }
124
124
 
125
- val request = DownloadManager.Request(Uri.parse(fileUrl))
126
- .setTitle(finalFileName)
127
- .setDescription("Dosya indiriliyor...")
128
- .setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
129
- .setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, finalFileName)
130
- .setAllowedOverMetered(true)
125
+ val uri = resolver.insert(
126
+ MediaStore.Downloads.EXTERNAL_CONTENT_URI,
127
+ values
128
+ ) ?: throw Exception("MediaStore dosya oluşturulamadı")
131
129
 
132
- if (cookie != null) request.addRequestHeader("Cookie", cookie)
133
- if (cleanContentType != "*/*") request.setMimeType(cleanContentType)
130
+ outputStream = resolver.openOutputStream(uri)
131
+ finalUri = uri.toString()
132
+ } else {
133
+ @Suppress("DEPRECATION")
134
+ val dir = Environment.getExternalStoragePublicDirectory(
135
+ Environment.DIRECTORY_DOWNLOADS
136
+ )
137
+ if (!dir.exists()) dir.mkdirs()
138
+
139
+ var file = File(dir, fileName)
140
+ var index = 1
141
+ val base = fileName.substringBeforeLast(".")
142
+ val ext = fileName.substringAfterLast(".", "")
134
143
 
135
- val downloadManager = reactContext.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
136
- val downloadId = downloadManager.enqueue(request)
144
+ while (file.exists()) {
145
+ val name = if (ext.isNotEmpty()) "$base($index).$ext" else "$base($index)"
146
+ file = File(dir, name)
147
+ index++
148
+ }
137
149
 
138
- downloadPromises[downloadId] = promise
150
+ outputStream = FileOutputStream(file)
151
+ finalUri = file.absolutePath
152
+ }
139
153
 
140
- } catch (e: Exception) {
141
- promise.reject("E_DOWNLOAD_SETUP_FAILED", e.message)
142
- } finally {
143
- connection?.disconnect()
154
+ // --- WRITE ---
155
+ val buffer = ByteArray(4096)
156
+ var count: Int
157
+ while (inputStream.read(buffer).also { count = it } != -1) {
158
+ outputStream?.write(buffer, 0, count)
144
159
  }
145
- }.start()
146
- }
147
160
 
148
- private fun checkDownloadStatus(id: Long, promise: Promise?) {
149
- val downloadManager = reactContext.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
150
- val query = DownloadManager.Query().setFilterById(id)
151
- val cursor = downloadManager.query(query)
161
+ outputStream?.flush()
162
+ resolveOnce(finalUri)
152
163
 
153
- if (cursor == null) {
154
- promise?.reject("E_DB_CURSOR_NULL", "Download cursor null")
155
- return
164
+ } catch (e: Exception) {
165
+ rejectOnce(
166
+ "ERR_DOWNLOAD",
167
+ e.message ?: "İndirme sırasında hata oluştu"
168
+ )
169
+ } finally {
170
+ try {
171
+ outputStream?.close()
172
+ inputStream?.close()
173
+ connection?.disconnect()
174
+ } catch (_: Exception) {
175
+ }
156
176
  }
177
+ }.start()
178
+ }
179
+
180
+ private fun getFileNameFromUrl(url: String, contentType: String?): String {
181
+ var name = try {
182
+ URLDecoder.decode(
183
+ URL(url).path.substringAfterLast('/'),
184
+ "UTF-8"
185
+ )
186
+ } catch (e: Exception) {
187
+ "downloaded_file"
188
+ }
157
189
 
158
- cursor.use {
159
- if (it.moveToFirst()) {
160
- val statusIndex = it.getColumnIndex(DownloadManager.COLUMN_STATUS)
161
- val status = if (statusIndex >= 0) it.getInt(statusIndex) else DownloadManager.STATUS_FAILED
162
-
163
- if (status == DownloadManager.STATUS_SUCCESSFUL) {
164
- val uriIndex = it.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI)
165
- val localUri = if (uriIndex >= 0) it.getString(uriIndex) else null
166
- promise?.resolve(localUri)
167
- } else {
168
- val reasonIndex = it.getColumnIndex(DownloadManager.COLUMN_REASON)
169
- val reason = if (reasonIndex >= 0) it.getInt(reasonIndex) else -1
170
- promise?.reject("E_DOWNLOAD_FAILED", "İndirme başarısız kod: $reason")
171
- }
172
- } else {
173
- promise?.reject("E_DOWNLOAD_NOT_FOUND", "İndirme kaydı bulunamadı.")
174
- }
190
+ if (name.isBlank()) name = "downloaded_file"
191
+
192
+ if (!name.contains(".") && !contentType.isNullOrEmpty()) {
193
+ val ext = MimeTypeMap.getSingleton()
194
+ .getExtensionFromMimeType(contentType)
195
+ if (ext != null) {
196
+ name += ".$ext"
175
197
  }
176
198
  }
199
+ return name
200
+ }
177
201
  }
@@ -10,6 +10,9 @@ import java.io.ByteArrayOutputStream
10
10
  import java.net.URLConnection
11
11
  import java.io.FileNotFoundException
12
12
  import android.util.Base64OutputStream
13
+ import android.graphics.Bitmap
14
+ import android.graphics.BitmapFactory
15
+ import android.graphics.Matrix
13
16
 
14
17
  class MyUploaderModule(private val reactContext: ReactApplicationContext) :
15
18
  ReactContextBaseJavaModule(reactContext), ActivityEventListener {
@@ -94,6 +97,76 @@ class MyUploaderModule(private val reactContext: ReactApplicationContext) :
94
97
  }
95
98
  }
96
99
 
100
+
101
+ @ReactMethod
102
+ fun rotateImage(base64String: String, angle: Double, promise: Promise) {
103
+ Thread {
104
+ try {
105
+ // 1. Base64 prefix temizleme
106
+ val cleanBase64 = if (base64String.contains(",")) {
107
+ base64String.substringAfter(",")
108
+ } else {
109
+ base64String
110
+ }
111
+
112
+ val decodedBytes = Base64.decode(cleanBase64, Base64.DEFAULT)
113
+
114
+ // 2. Bitmap decode (RAM güvenli)
115
+ val options = BitmapFactory.Options().apply {
116
+ inPreferredConfig = Bitmap.Config.ARGB_8888
117
+ }
118
+
119
+ val originalBitmap =
120
+ BitmapFactory.decodeByteArray(decodedBytes, 0, decodedBytes.size, options)
121
+
122
+ if (originalBitmap == null) {
123
+ reactContext.runOnUiQueueThread {
124
+ promise.reject("E_DECODE_ERROR", "Görüntü çözümlenemedi.")
125
+ }
126
+ return@Thread
127
+ }
128
+
129
+ // 3. Rotate
130
+ val matrix = Matrix()
131
+ matrix.postRotate(angle.toFloat())
132
+
133
+ val rotatedBitmap = Bitmap.createBitmap(
134
+ originalBitmap,
135
+ 0,
136
+ 0,
137
+ originalBitmap.width,
138
+ originalBitmap.height,
139
+ matrix,
140
+ true
141
+ )
142
+
143
+ // 4. Base64 encode
144
+ val outputStream = ByteArrayOutputStream()
145
+ rotatedBitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream)
146
+
147
+ val encodedString = Base64.encodeToString(
148
+ outputStream.toByteArray(),
149
+ Base64.NO_WRAP
150
+ )
151
+
152
+ // 5. Memory cleanup
153
+ originalBitmap.recycle()
154
+ rotatedBitmap.recycle()
155
+
156
+ // 6. Promise → UI Thread
157
+ reactContext.runOnUiQueueThread {
158
+ promise.resolve(encodedString)
159
+ }
160
+
161
+ } catch (e: Exception) {
162
+ reactContext.runOnUiQueueThread {
163
+ promise.reject("E_ROTATE_ERROR", "Rotate failed: ${e.message}")
164
+ }
165
+ }
166
+ }.start()
167
+ }
168
+
169
+
97
170
  override fun onActivityResult(activity: Activity, requestCode: Int, resultCode: Int, data: Intent?) {
98
171
  if (requestCode != REQUEST_CODE || pickerPromise == null) { return }
99
172
 
@@ -3,12 +3,12 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.default = void 0;
6
+ exports.DownloadFile = void 0;
7
7
  var _react = _interopRequireWildcard(require("react"));
8
8
  var _reactNative = require("react-native");
9
9
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
10
10
  const {
11
- DownloadFile: NativeDownload
11
+ DownloadFileModule
12
12
  } = _reactNative.NativeModules;
13
13
  const DownloadFile = ({
14
14
  files,
@@ -16,7 +16,7 @@ const DownloadFile = ({
16
16
  disabled = false,
17
17
  debug = false,
18
18
  maxSize = 0,
19
- fileTypes = ['*/*'],
19
+ fileTypes = [],
20
20
  buttonPlaceHolder = 'Dosyaları İndir',
21
21
  buttonIcon,
22
22
  ButtonStyle,
@@ -25,6 +25,14 @@ const DownloadFile = ({
25
25
  onError
26
26
  }) => {
27
27
  const [isLoading, setIsLoading] = (0, _react.useState)(false);
28
+ if (!DownloadFileModule) {
29
+ console.warn("DownloadFileModule bulunamadı. Native tarafın kurulduğundan emin olun.");
30
+ return null;
31
+ }
32
+ const NativeDownloadModuleWrapper = (url, options) => {
33
+ // 🔥 Kotlin Promise metoduyla birebir uyumlu
34
+ return DownloadFileModule.downloadFile(url, options);
35
+ };
28
36
  const handlePress = async () => {
29
37
  if (disabled || isLoading || !files.length) return;
30
38
  setIsLoading(true);
@@ -33,33 +41,57 @@ const DownloadFile = ({
33
41
  maxSize,
34
42
  fileTypes
35
43
  };
36
- const targetFiles = multipleDownload ? files : [files[0]];
44
+
45
+ // ✅ undefined güvenli
46
+ const targetFiles = (multipleDownload ? files : [files[0]]).filter(file => typeof file === 'string' && file.trim().length > 0);
47
+ const sizeErrors = [];
48
+ const typeErrors = [];
49
+ const otherErrors = [];
50
+ const successFiles = [];
37
51
  try {
38
- const promises = targetFiles.map(url => NativeDownload.downloadFile(url, options));
52
+ const promises = targetFiles.map(url => NativeDownloadModuleWrapper(url, options));
39
53
  const results = await Promise.allSettled(promises);
40
- const final = {
41
- successful: [],
42
- skipped: []
43
- };
44
54
  results.forEach((res, index) => {
45
- var _targetFiles$index;
55
+ var _targetFiles$index, _originalUrl$split$po;
46
56
  const originalUrl = (_targetFiles$index = targetFiles[index]) !== null && _targetFiles$index !== void 0 ? _targetFiles$index : "";
57
+ const fileName = ((_originalUrl$split$po = originalUrl.split('/').pop()) === null || _originalUrl$split$po === void 0 ? void 0 : _originalUrl$split$po.split('?')[0]) || `Dosya ${index + 1}`;
47
58
  if (res.status === 'fulfilled') {
48
- final.successful.push({
59
+ successFiles.push({
49
60
  originalUrl,
50
61
  localUri: res.value
51
62
  });
52
63
  } else {
53
- var _res$reason;
54
- final.skipped.push({
55
- originalUrl,
56
- reason: ((_res$reason = res.reason) === null || _res$reason === void 0 ? void 0 : _res$reason.message) || "Bilinmeyen Hata"
57
- });
64
+ var _res$reason, _res$reason2;
65
+ const errorCode = (_res$reason = res.reason) === null || _res$reason === void 0 ? void 0 : _res$reason.code;
66
+ const errorMsg = ((_res$reason2 = res.reason) === null || _res$reason2 === void 0 ? void 0 : _res$reason2.message) || 'Bilinmeyen hata';
67
+ if (errorCode === 'ERR_SIZE_LIMIT') {
68
+ sizeErrors.push(fileName);
69
+ } else if (errorCode === 'ERR_TYPE_MISMATCH') {
70
+ typeErrors.push(fileName);
71
+ } else {
72
+ otherErrors.push(`${fileName}: ${errorMsg}`);
73
+ }
58
74
  }
59
75
  });
60
- if (onSuccess) onSuccess(final);
76
+ if (sizeErrors.length > 0) {
77
+ _reactNative.Alert.alert('Boyut Sınırı Aşıldı', `Aşağıdaki dosyalar ${maxSize}MB sınırını aştığı için indirilemedi:\n\n${sizeErrors.join('\n')}`);
78
+ }
79
+ if (typeErrors.length > 0) {
80
+ _reactNative.Alert.alert('Desteklenmeyen Dosya Tipi', `Sadece şu formatlar izin verilmektedir: [${fileTypes.join(', ')}]\n\nUygun olmayan dosyalar:\n\n${typeErrors.join('\n')}`);
81
+ }
82
+ if (otherErrors.length > 0 && debug) {
83
+ _reactNative.Alert.alert('İndirme Hatası', otherErrors.join('\n'));
84
+ }
85
+ const finalResult = {
86
+ successful: successFiles,
87
+ skipped: [...sizeErrors, ...typeErrors, ...otherErrors].map(name => ({
88
+ originalUrl: name,
89
+ reason: 'Failed'
90
+ }))
91
+ };
92
+ onSuccess === null || onSuccess === void 0 || onSuccess(finalResult);
61
93
  } catch (e) {
62
- if (onError) onError(e);else console.error(e);
94
+ onError === null || onError === void 0 || onError(e);
63
95
  } finally {
64
96
  setIsLoading(false);
65
97
  }
@@ -70,10 +102,11 @@ const DownloadFile = ({
70
102
  disabled: disabled || isLoading
71
103
  }, isLoading ? /*#__PURE__*/_react.default.createElement(_reactNative.ActivityIndicator, {
72
104
  color: "#FFF"
73
- }) : buttonIcon ? buttonIcon : /*#__PURE__*/_react.default.createElement(_reactNative.Text, {
105
+ }) : buttonIcon || /*#__PURE__*/_react.default.createElement(_reactNative.Text, {
74
106
  style: [styles.text, ButtonTextStyle]
75
107
  }, buttonPlaceHolder));
76
108
  };
109
+ exports.DownloadFile = DownloadFile;
77
110
  const styles = _reactNative.StyleSheet.create({
78
111
  button: {
79
112
  backgroundColor: '#03DAC6',
@@ -89,5 +122,4 @@ const styles = _reactNative.StyleSheet.create({
89
122
  backgroundColor: '#AAA'
90
123
  }
91
124
  });
92
- var _default = exports.default = DownloadFile;
93
125
  //# sourceMappingURL=DownloadFile.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["_react","_interopRequireWildcard","require","_reactNative","e","t","WeakMap","r","n","__esModule","o","i","f","__proto__","default","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","DownloadFile","NativeDownload","NativeModules","files","multipleDownload","disabled","debug","maxSize","fileTypes","buttonPlaceHolder","buttonIcon","ButtonStyle","ButtonTextStyle","onSuccess","onError","isLoading","setIsLoading","useState","handlePress","length","options","targetFiles","promises","map","url","downloadFile","results","Promise","allSettled","final","successful","skipped","forEach","res","index","_targetFiles$index","originalUrl","status","push","localUri","value","_res$reason","reason","message","console","error","createElement","TouchableOpacity","style","styles","button","onPress","ActivityIndicator","color","Text","text","StyleSheet","create","backgroundColor","padding","borderRadius","alignItems","fontWeight","_default","exports"],"sources":["DownloadFile.tsx"],"sourcesContent":["import React, { useState } from 'react';\r\nimport { TouchableOpacity, Text, StyleSheet, ActivityIndicator,NativeModules } from 'react-native';\r\nimport type { DownloadFileProps, DownloadResult } from '../types';\r\n\r\n\r\nconst { DownloadFile: NativeDownload } = NativeModules;\r\n\r\n\r\nconst DownloadFile: React.FC<DownloadFileProps> = ({\r\n files,\r\n multipleDownload = false,\r\n disabled = false,\r\n debug = false,\r\n maxSize = 0,\r\n fileTypes = ['*/*'],\r\n buttonPlaceHolder = 'Dosyaları İndir',\r\n buttonIcon,\r\n ButtonStyle,\r\n ButtonTextStyle,\r\n onSuccess,\r\n onError,\r\n}) => {\r\n const [isLoading, setIsLoading] = useState(false);\r\n\r\n const handlePress = async () => {\r\n if (disabled || isLoading || !files.length) return;\r\n setIsLoading(true);\r\n\r\n const options = { debug, maxSize, fileTypes };\r\n const targetFiles = multipleDownload ? files : [files[0]];\r\n\r\n try {\r\n const promises = targetFiles.map(url => NativeDownload.downloadFile(url, options));\r\n const results = await Promise.allSettled(promises);\r\n \r\n const final: DownloadResult = { successful: [], skipped: [] };\r\n\r\n results.forEach((res, index) => {\r\n const originalUrl = targetFiles[index] ?? \"\";\r\n if (res.status === 'fulfilled') {\r\n final.successful.push({ originalUrl, localUri: res.value });\r\n } else {\r\n final.skipped.push({ \r\n originalUrl, \r\n reason: res.reason?.message || \"Bilinmeyen Hata\" \r\n });\r\n }\r\n });\r\n\r\n if (onSuccess) onSuccess(final);\r\n } catch (e) {\r\n if (onError) onError(e);\r\n else console.error(e);\r\n } finally {\r\n setIsLoading(false);\r\n }\r\n };\r\n\r\n return (\r\n <TouchableOpacity\r\n style={[styles.button, ButtonStyle, (disabled || isLoading) && styles.disabled]}\r\n onPress={handlePress}\r\n disabled={disabled || isLoading}\r\n >\r\n {isLoading ? (\r\n <ActivityIndicator color=\"#FFF\" />\r\n ) : (\r\n buttonIcon ? buttonIcon : <Text style={[styles.text, ButtonTextStyle]}>{buttonPlaceHolder}</Text>\r\n )}\r\n </TouchableOpacity>\r\n );\r\n};\r\n\r\nconst styles = StyleSheet.create({\r\n button: {\r\n backgroundColor: '#03DAC6',\r\n padding: 12,\r\n borderRadius: 8,\r\n alignItems: 'center',\r\n },\r\n text: { color: '#000', fontWeight: 'bold' },\r\n disabled: { backgroundColor: '#AAA' }\r\n});\r\n\r\nexport default DownloadFile;"],"mappings":";;;;;;AAAA,IAAAA,MAAA,GAAAC,uBAAA,CAAAC,OAAA;AACA,IAAAC,YAAA,GAAAD,OAAA;AAAmG,SAAAD,wBAAAG,CAAA,EAAAC,CAAA,6BAAAC,OAAA,MAAAC,CAAA,OAAAD,OAAA,IAAAE,CAAA,OAAAF,OAAA,YAAAL,uBAAA,YAAAA,CAAAG,CAAA,EAAAC,CAAA,SAAAA,CAAA,IAAAD,CAAA,IAAAA,CAAA,CAAAK,UAAA,SAAAL,CAAA,MAAAM,CAAA,EAAAC,CAAA,EAAAC,CAAA,KAAAC,SAAA,QAAAC,OAAA,EAAAV,CAAA,iBAAAA,CAAA,uBAAAA,CAAA,yBAAAA,CAAA,SAAAQ,CAAA,MAAAF,CAAA,GAAAL,CAAA,GAAAG,CAAA,GAAAD,CAAA,QAAAG,CAAA,CAAAK,GAAA,CAAAX,CAAA,UAAAM,CAAA,CAAAM,GAAA,CAAAZ,CAAA,GAAAM,CAAA,CAAAO,GAAA,CAAAb,CAAA,EAAAQ,CAAA,gBAAAP,CAAA,IAAAD,CAAA,gBAAAC,CAAA,OAAAa,cAAA,CAAAC,IAAA,CAAAf,CAAA,EAAAC,CAAA,OAAAM,CAAA,IAAAD,CAAA,GAAAU,MAAA,CAAAC,cAAA,KAAAD,MAAA,CAAAE,wBAAA,CAAAlB,CAAA,EAAAC,CAAA,OAAAM,CAAA,CAAAK,GAAA,IAAAL,CAAA,CAAAM,GAAA,IAAAP,CAAA,CAAAE,CAAA,EAAAP,CAAA,EAAAM,CAAA,IAAAC,CAAA,CAAAP,CAAA,IAAAD,CAAA,CAAAC,CAAA,WAAAO,CAAA,KAAAR,CAAA,EAAAC,CAAA;AAInG,MAAM;EAAEkB,YAAY,EAAEC;AAAe,CAAC,GAAGC,0BAAa;AAGtD,MAAMF,YAAyC,GAAGA,CAAC;EACjDG,KAAK;EACLC,gBAAgB,GAAG,KAAK;EACxBC,QAAQ,GAAG,KAAK;EAChBC,KAAK,GAAG,KAAK;EACbC,OAAO,GAAG,CAAC;EACXC,SAAS,GAAG,CAAC,KAAK,CAAC;EACnBC,iBAAiB,GAAG,iBAAiB;EACrCC,UAAU;EACVC,WAAW;EACXC,eAAe;EACfC,SAAS;EACTC;AACF,CAAC,KAAK;EACJ,MAAM,CAACC,SAAS,EAAEC,YAAY,CAAC,GAAG,IAAAC,eAAQ,EAAC,KAAK,CAAC;EAEjD,MAAMC,WAAW,GAAG,MAAAA,CAAA,KAAY;IAC9B,IAAIb,QAAQ,IAAIU,SAAS,IAAI,CAACZ,KAAK,CAACgB,MAAM,EAAE;IAC5CH,YAAY,CAAC,IAAI,CAAC;IAElB,MAAMI,OAAO,GAAG;MAAEd,KAAK;MAAEC,OAAO;MAAEC;IAAU,CAAC;IAC7C,MAAMa,WAAW,GAAGjB,gBAAgB,GAAGD,KAAK,GAAG,CAACA,KAAK,CAAC,CAAC,CAAC,CAAC;IAEzD,IAAI;MACF,MAAMmB,QAAQ,GAAGD,WAAW,CAACE,GAAG,CAACC,GAAG,IAAIvB,cAAc,CAACwB,YAAY,CAACD,GAAG,EAAEJ,OAAO,CAAC,CAAC;MAClF,MAAMM,OAAO,GAAG,MAAMC,OAAO,CAACC,UAAU,CAACN,QAAQ,CAAC;MAElD,MAAMO,KAAqB,GAAG;QAAEC,UAAU,EAAE,EAAE;QAAEC,OAAO,EAAE;MAAG,CAAC;MAE7DL,OAAO,CAACM,OAAO,CAAC,CAACC,GAAG,EAAEC,KAAK,KAAK;QAAA,IAAAC,kBAAA;QAC9B,MAAMC,WAAW,IAAAD,kBAAA,GAAGd,WAAW,CAACa,KAAK,CAAC,cAAAC,kBAAA,cAAAA,kBAAA,GAAI,EAAE;QAC5C,IAAIF,GAAG,CAACI,MAAM,KAAK,WAAW,EAAE;UAC9BR,KAAK,CAACC,UAAU,CAACQ,IAAI,CAAC;YAAEF,WAAW;YAAEG,QAAQ,EAAEN,GAAG,CAACO;UAAM,CAAC,CAAC;QAC7D,CAAC,MAAM;UAAA,IAAAC,WAAA;UACLZ,KAAK,CAACE,OAAO,CAACO,IAAI,CAAC;YACjBF,WAAW;YACXM,MAAM,EAAE,EAAAD,WAAA,GAAAR,GAAG,CAACS,MAAM,cAAAD,WAAA,uBAAVA,WAAA,CAAYE,OAAO,KAAI;UACjC,CAAC,CAAC;QACJ;MACF,CAAC,CAAC;MAEF,IAAI9B,SAAS,EAAEA,SAAS,CAACgB,KAAK,CAAC;IACjC,CAAC,CAAC,OAAOhD,CAAC,EAAE;MACV,IAAIiC,OAAO,EAAEA,OAAO,CAACjC,CAAC,CAAC,CAAC,KACnB+D,OAAO,CAACC,KAAK,CAAChE,CAAC,CAAC;IACvB,CAAC,SAAS;MACRmC,YAAY,CAAC,KAAK,CAAC;IACrB;EACF,CAAC;EAED,oBACEvC,MAAA,CAAAc,OAAA,CAAAuD,aAAA,CAAClE,YAAA,CAAAmE,gBAAgB;IACfC,KAAK,EAAE,CAACC,MAAM,CAACC,MAAM,EAAEvC,WAAW,EAAE,CAACN,QAAQ,IAAIU,SAAS,KAAKkC,MAAM,CAAC5C,QAAQ,CAAE;IAChF8C,OAAO,EAAEjC,WAAY;IACrBb,QAAQ,EAAEA,QAAQ,IAAIU;EAAU,GAE/BA,SAAS,gBACRtC,MAAA,CAAAc,OAAA,CAAAuD,aAAA,CAAClE,YAAA,CAAAwE,iBAAiB;IAACC,KAAK,EAAC;EAAM,CAAE,CAAC,GAElC3C,UAAU,GAAGA,UAAU,gBAAGjC,MAAA,CAAAc,OAAA,CAAAuD,aAAA,CAAClE,YAAA,CAAA0E,IAAI;IAACN,KAAK,EAAE,CAACC,MAAM,CAACM,IAAI,EAAE3C,eAAe;EAAE,GAAEH,iBAAwB,CAElF,CAAC;AAEvB,CAAC;AAED,MAAMwC,MAAM,GAAGO,uBAAU,CAACC,MAAM,CAAC;EAC/BP,MAAM,EAAE;IACNQ,eAAe,EAAE,SAAS;IAC1BC,OAAO,EAAE,EAAE;IACXC,YAAY,EAAE,CAAC;IACfC,UAAU,EAAE;EACd,CAAC;EACDN,IAAI,EAAE;IAAEF,KAAK,EAAE,MAAM;IAAES,UAAU,EAAE;EAAO,CAAC;EAC3CzD,QAAQ,EAAE;IAAEqD,eAAe,EAAE;EAAO;AACtC,CAAC,CAAC;AAAC,IAAAK,QAAA,GAAAC,OAAA,CAAAzE,OAAA,GAEYS,YAAY","ignoreList":[]}
1
+ {"version":3,"names":["_react","_interopRequireWildcard","require","_reactNative","e","t","WeakMap","r","n","__esModule","o","i","f","__proto__","default","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","DownloadFileModule","NativeModules","DownloadFile","files","multipleDownload","disabled","debug","maxSize","fileTypes","buttonPlaceHolder","buttonIcon","ButtonStyle","ButtonTextStyle","onSuccess","onError","isLoading","setIsLoading","useState","console","warn","NativeDownloadModuleWrapper","url","options","downloadFile","handlePress","length","targetFiles","filter","file","trim","sizeErrors","typeErrors","otherErrors","successFiles","promises","map","results","Promise","allSettled","forEach","res","index","_targetFiles$index","_originalUrl$split$po","originalUrl","fileName","split","pop","status","push","localUri","value","_res$reason","_res$reason2","errorCode","reason","code","errorMsg","message","Alert","alert","join","finalResult","successful","skipped","name","createElement","TouchableOpacity","style","styles","button","onPress","ActivityIndicator","color","Text","text","exports","StyleSheet","create","backgroundColor","padding","borderRadius","alignItems","fontWeight"],"sources":["DownloadFile.tsx"],"sourcesContent":["import React, { useState } from 'react';\r\nimport {\r\n TouchableOpacity,\r\n Text,\r\n StyleSheet,\r\n ActivityIndicator,\r\n NativeModules,\r\n Alert,\r\n} from 'react-native';\r\nimport type { DownloadFileProps, DownloadResult } from '../types';\r\n\r\nconst { DownloadFileModule } = NativeModules;\r\n\r\nexport const DownloadFile: React.FC<DownloadFileProps> = ({\r\n files,\r\n multipleDownload = false,\r\n disabled = false,\r\n debug = false,\r\n maxSize = 0,\r\n fileTypes = [],\r\n buttonPlaceHolder = 'Dosyaları İndir',\r\n buttonIcon,\r\n ButtonStyle,\r\n ButtonTextStyle,\r\n onSuccess,\r\n onError,\r\n}) => {\r\n const [isLoading, setIsLoading] = useState(false);\r\n\r\n if (!DownloadFileModule) {\r\n console.warn(\"DownloadFileModule bulunamadı. Native tarafın kurulduğundan emin olun.\");\r\n return null;\r\n }\r\n\r\n const NativeDownloadModuleWrapper = (\r\n url: string,\r\n options: any\r\n ): Promise<string> => {\r\n // 🔥 Kotlin Promise metoduyla birebir uyumlu\r\n return DownloadFileModule.downloadFile(url, options);\r\n };\r\n\r\n const handlePress = async () => {\r\n if (disabled || isLoading || !files.length) return;\r\n setIsLoading(true);\r\n\r\n const options = { debug, maxSize, fileTypes };\r\n\r\n // ✅ undefined güvenli\r\n const targetFiles: string[] = (\r\n multipleDownload ? files : [files[0]]\r\n ).filter((file): file is string => typeof file === 'string' && file.trim().length > 0);\r\n\r\n const sizeErrors: string[] = [];\r\n const typeErrors: string[] = [];\r\n const otherErrors: string[] = [];\r\n const successFiles: DownloadResult['successful'] = [];\r\n\r\n try {\r\n const promises = targetFiles.map(url =>\r\n NativeDownloadModuleWrapper(url, options)\r\n );\r\n\r\n const results = await Promise.allSettled(promises);\r\n\r\n results.forEach((res, index) => {\r\n const originalUrl = targetFiles[index] ?? \"\";\r\n const fileName =\r\n originalUrl.split('/').pop()?.split('?')[0] ||\r\n `Dosya ${index + 1}`;\r\n\r\n if (res.status === 'fulfilled') {\r\n successFiles.push({\r\n originalUrl,\r\n localUri: res.value,\r\n });\r\n } else {\r\n const errorCode = res.reason?.code;\r\n const errorMsg = res.reason?.message || 'Bilinmeyen hata';\r\n\r\n if (errorCode === 'ERR_SIZE_LIMIT') {\r\n sizeErrors.push(fileName);\r\n } else if (errorCode === 'ERR_TYPE_MISMATCH') {\r\n typeErrors.push(fileName);\r\n } else {\r\n otherErrors.push(`${fileName}: ${errorMsg}`);\r\n }\r\n }\r\n });\r\n\r\n if (sizeErrors.length > 0) {\r\n Alert.alert(\r\n 'Boyut Sınırı Aşıldı',\r\n `Aşağıdaki dosyalar ${maxSize}MB sınırını aştığı için indirilemedi:\\n\\n${sizeErrors.join(\r\n '\\n'\r\n )}`\r\n );\r\n }\r\n\r\n if (typeErrors.length > 0) {\r\n Alert.alert(\r\n 'Desteklenmeyen Dosya Tipi',\r\n `Sadece şu formatlar izin verilmektedir: [${fileTypes.join(\r\n ', '\r\n )}]\\n\\nUygun olmayan dosyalar:\\n\\n${typeErrors.join('\\n')}`\r\n );\r\n }\r\n\r\n if (otherErrors.length > 0 && debug) {\r\n Alert.alert('İndirme Hatası', otherErrors.join('\\n'));\r\n }\r\n\r\n const finalResult: DownloadResult = {\r\n successful: successFiles,\r\n skipped: [...sizeErrors, ...typeErrors, ...otherErrors].map(\r\n name => ({\r\n originalUrl: name,\r\n reason: 'Failed',\r\n })\r\n ),\r\n };\r\n\r\n onSuccess?.(finalResult);\r\n } catch (e) {\r\n onError?.(e);\r\n } finally {\r\n setIsLoading(false);\r\n }\r\n };\r\n\r\n return (\r\n <TouchableOpacity\r\n style={[styles.button, ButtonStyle, (disabled || isLoading) && styles.disabled]}\r\n onPress={handlePress}\r\n disabled={disabled || isLoading}\r\n >\r\n {isLoading ? (\r\n <ActivityIndicator color=\"#FFF\" />\r\n ) : (\r\n buttonIcon || (\r\n <Text style={[styles.text, ButtonTextStyle]}>\r\n {buttonPlaceHolder}\r\n </Text>\r\n )\r\n )}\r\n </TouchableOpacity>\r\n );\r\n};\r\n\r\nconst styles = StyleSheet.create({\r\n button: {\r\n backgroundColor: '#03DAC6',\r\n padding: 12,\r\n borderRadius: 8,\r\n alignItems: 'center',\r\n },\r\n text: {\r\n color: '#000',\r\n fontWeight: 'bold',\r\n },\r\n disabled: {\r\n backgroundColor: '#AAA',\r\n },\r\n});\r\n\r\n"],"mappings":"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","ignoreList":[]}
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.pickFile = exports.default = void 0;
6
+ exports.pickFile = exports.default = exports.RotateImage = void 0;
7
7
  var _react = _interopRequireWildcard(require("react"));
8
8
  var _reactNative = require("react-native");
9
9
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
@@ -26,9 +26,26 @@ const pickFile = async (options = {}) => {
26
26
  };
27
27
  return await NativeUploadPicker.openDocument(nativeOptions);
28
28
  };
29
+ exports.pickFile = pickFile;
30
+ const RotateImage = async ({
31
+ base64,
32
+ angle
33
+ }) => {
34
+ if (!NativeUploadPicker) {
35
+ throw new Error("UploadDocumentPicker module is not linked.");
36
+ }
37
+ try {
38
+ const rotatedBase64 = await NativeUploadPicker.rotateImage(base64, angle);
39
+
40
+ // JS tarafında prefix eklenir
41
+ return `data:image/jpeg;base64,${rotatedBase64}`;
42
+ } catch (error) {
43
+ throw new Error(`RotateImage Error: ${error.message}`);
44
+ }
45
+ };
29
46
 
30
47
  // 2. MyUploader Bileşeni
31
- exports.pickFile = pickFile;
48
+ exports.RotateImage = RotateImage;
32
49
  const MyUploader = ({
33
50
  onSelect,
34
51
  onError,