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

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
  }
@@ -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":"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","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":[]}
@@ -1 +1 @@
1
- {"version":3,"names":["_types","require","Object","keys","forEach","key","exports","defineProperty","enumerable","get"],"sources":["index.d.ts"],"sourcesContent":["import * as React from 'react';\r\nimport type { DocumentPickerOptions, MyUploaderProps, FileInfo } from './types';\r\n// import type { DownloadFileProps } from './types';\r\n\r\nexport * from './types';\r\n\r\n// DownloadFile Component Tanımı (3. Bunu ekledik)\r\n// export declare const DownloadFile: React.FC<DownloadFileProps>;\r\n\r\n// pickFile Fonksiyon Tanımı\r\nexport declare function pickFile(options?: DocumentPickerOptions): Promise<FileInfo[]>;\r\n\r\nexport declare const MyUploader: React.FC<MyUploaderProps>;\r\n\r\n// Varsayılan dışa aktarım (İsteğe bağlı, genellikle ana bileşen verilir)\r\ndeclare const _default: React.FC<MyUploaderProps>;\r\nexport default _default;"],"mappings":";;;;;AAIA,IAAAA,MAAA,GAAAC,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAH,MAAA,EAAAI,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAL,MAAA,CAAAK,GAAA;EAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA;IAAAG,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAT,MAAA,CAAAK,GAAA;IAAA;EAAA;AAAA","ignoreList":[]}
1
+ {"version":3,"names":["_types","require","Object","keys","forEach","key","exports","defineProperty","enumerable","get"],"sources":["index.d.ts"],"sourcesContent":["import * as React from 'react';\r\nimport type { DocumentPickerOptions, MyUploaderProps, FileInfo, DownloadFileProps } from './types';\r\n// import type { DownloadFileProps } from './types';\r\n\r\nexport * from './types';\r\n\r\n// DownloadFile Component Tanımı (3. Bunu ekledik)\r\n// export declare const DownloadFile: React.FC<DownloadFileProps>;\r\n\r\n// pickFile Fonksiyon Tanımı\r\nexport declare function pickFile(options?: DocumentPickerOptions): Promise<FileInfo[]>;\r\nexport declare const DownloadFile :React.FC<DownloadFileProps>;\r\nexport declare const MyUploader: React.FC<MyUploaderProps>;\r\n\r\n// Varsayılan dışa aktarım (İsteğe bağlı, genellikle ana bileşen verilir)\r\ndeclare const _default: React.FC<MyUploaderProps>;\r\nexport default _default;"],"mappings":";;;;;AAIA,IAAAA,MAAA,GAAAC,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAH,MAAA,EAAAI,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAL,MAAA,CAAAK,GAAA;EAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA;IAAAG,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAT,MAAA,CAAAK,GAAA;IAAA;EAAA;AAAA","ignoreList":[]}
@@ -5,8 +5,15 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  var _exportNames = {
7
7
  MyUploader: true,
8
- pickFile: true
8
+ pickFile: true,
9
+ DownloadFile: true
9
10
  };
11
+ Object.defineProperty(exports, "DownloadFile", {
12
+ enumerable: true,
13
+ get: function () {
14
+ return _DownloadFile.DownloadFile;
15
+ }
16
+ });
10
17
  Object.defineProperty(exports, "MyUploader", {
11
18
  enumerable: true,
12
19
  get: function () {
@@ -21,6 +28,7 @@ Object.defineProperty(exports, "pickFile", {
21
28
  }
22
29
  });
23
30
  var _MyUploader = _interopRequireWildcard(require("./components/MyUploader"));
31
+ var _DownloadFile = require("./components/DownloadFile");
24
32
  var _types = require("./types");
25
33
  Object.keys(_types).forEach(function (key) {
26
34
  if (key === "default" || key === "__esModule") return;
@@ -34,9 +42,6 @@ Object.keys(_types).forEach(function (key) {
34
42
  });
35
43
  });
36
44
  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); }
37
- // import DownloadFile from "./components/DownloadFile";
38
- // 2. Diğerlerini NAMED olarak dışa aktar (import { DownloadFile, pickFile } ... için)
39
- // export { DownloadFile, pickFile };
40
45
  // Sadece bu paketle ilgili olanları dışa aktar
41
46
  // Varsayılan dışa aktarım olarak da ana bileşeni verelim
42
47
  var _default = exports.default = _MyUploader.default;
@@ -1 +1 @@
1
- {"version":3,"names":["_MyUploader","_interopRequireWildcard","require","_types","Object","keys","forEach","key","prototype","hasOwnProperty","call","_exportNames","exports","defineProperty","enumerable","get","e","t","WeakMap","r","n","__esModule","o","i","f","__proto__","default","has","set","getOwnPropertyDescriptor","_default","MyUploader"],"sources":["index.ts"],"sourcesContent":["import MyUploader,{pickFile} from \"./components/MyUploader\";\r\n// import DownloadFile from \"./components/DownloadFile\";\r\n\r\n// 2. Diğerlerini NAMED olarak dışa aktar (import { DownloadFile, pickFile } ... için)\r\n// export { DownloadFile, pickFile };\r\n\r\n\r\n// Sadece bu paketle ilgili olanları dışa aktar\r\nexport { MyUploader, pickFile };\r\nexport * from './types';\r\n\r\n// Varsayılan dışa aktarım olarak da ana bileşeni verelim\r\nexport default MyUploader;\r\n\r\n\r\n\r\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAAA,IAAAA,WAAA,GAAAC,uBAAA,CAAAC,OAAA;AASA,IAAAC,MAAA,GAAAD,OAAA;AAAAE,MAAA,CAAAC,IAAA,CAAAF,MAAA,EAAAG,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAH,MAAA,CAAAI,SAAA,CAAAC,cAAA,CAAAC,IAAA,CAAAC,YAAA,EAAAJ,GAAA;EAAA,IAAAA,GAAA,IAAAK,OAAA,IAAAA,OAAA,CAAAL,GAAA,MAAAJ,MAAA,CAAAI,GAAA;EAAAH,MAAA,CAAAS,cAAA,CAAAD,OAAA,EAAAL,GAAA;IAAAO,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAZ,MAAA,CAAAI,GAAA;IAAA;EAAA;AAAA;AAAwB,SAAAN,wBAAAe,CAAA,EAAAC,CAAA,6BAAAC,OAAA,MAAAC,CAAA,OAAAD,OAAA,IAAAE,CAAA,OAAAF,OAAA,YAAAjB,uBAAA,YAAAA,CAAAe,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,CAAAP,GAAA,CAAAC,CAAA,GAAAM,CAAA,CAAAM,GAAA,CAAAZ,CAAA,EAAAQ,CAAA,gBAAAP,CAAA,IAAAD,CAAA,gBAAAC,CAAA,OAAAR,cAAA,CAAAC,IAAA,CAAAM,CAAA,EAAAC,CAAA,OAAAM,CAAA,IAAAD,CAAA,GAAAlB,MAAA,CAAAS,cAAA,KAAAT,MAAA,CAAAyB,wBAAA,CAAAb,CAAA,EAAAC,CAAA,OAAAM,CAAA,CAAAR,GAAA,IAAAQ,CAAA,CAAAK,GAAA,IAAAN,CAAA,CAAAE,CAAA,EAAAP,CAAA,EAAAM,CAAA,IAAAC,CAAA,CAAAP,CAAA,IAAAD,CAAA,CAAAC,CAAA,WAAAO,CAAA,KAAAR,CAAA,EAAAC,CAAA;AARxB;AAEA;AACA;AAGA;AAIA;AAAA,IAAAa,QAAA,GAAAlB,OAAA,CAAAc,OAAA,GACeK,mBAAU","ignoreList":[]}
1
+ {"version":3,"names":["_MyUploader","_interopRequireWildcard","require","_DownloadFile","_types","Object","keys","forEach","key","prototype","hasOwnProperty","call","_exportNames","exports","defineProperty","enumerable","get","e","t","WeakMap","r","n","__esModule","o","i","f","__proto__","default","has","set","getOwnPropertyDescriptor","_default","MyUploader"],"sources":["index.ts"],"sourcesContent":["import MyUploader,{pickFile} from \"./components/MyUploader\";\r\nimport {DownloadFile} from \"./components/DownloadFile\";\r\n\r\n\r\n// Sadece bu paketle ilgili olanları dışa aktar\r\nexport { MyUploader, pickFile ,DownloadFile };\r\nexport * from './types';\r\n\r\n// Varsayılan dışa aktarım olarak da ana bileşeni verelim\r\nexport default MyUploader;\r\n\r\n\r\n\r\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,IAAAA,WAAA,GAAAC,uBAAA,CAAAC,OAAA;AACA,IAAAC,aAAA,GAAAD,OAAA;AAKA,IAAAE,MAAA,GAAAF,OAAA;AAAAG,MAAA,CAAAC,IAAA,CAAAF,MAAA,EAAAG,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAH,MAAA,CAAAI,SAAA,CAAAC,cAAA,CAAAC,IAAA,CAAAC,YAAA,EAAAJ,GAAA;EAAA,IAAAA,GAAA,IAAAK,OAAA,IAAAA,OAAA,CAAAL,GAAA,MAAAJ,MAAA,CAAAI,GAAA;EAAAH,MAAA,CAAAS,cAAA,CAAAD,OAAA,EAAAL,GAAA;IAAAO,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAZ,MAAA,CAAAI,GAAA;IAAA;EAAA;AAAA;AAAwB,SAAAP,wBAAAgB,CAAA,EAAAC,CAAA,6BAAAC,OAAA,MAAAC,CAAA,OAAAD,OAAA,IAAAE,CAAA,OAAAF,OAAA,YAAAlB,uBAAA,YAAAA,CAAAgB,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,CAAAP,GAAA,CAAAC,CAAA,GAAAM,CAAA,CAAAM,GAAA,CAAAZ,CAAA,EAAAQ,CAAA,gBAAAP,CAAA,IAAAD,CAAA,gBAAAC,CAAA,OAAAR,cAAA,CAAAC,IAAA,CAAAM,CAAA,EAAAC,CAAA,OAAAM,CAAA,IAAAD,CAAA,GAAAlB,MAAA,CAAAS,cAAA,KAAAT,MAAA,CAAAyB,wBAAA,CAAAb,CAAA,EAAAC,CAAA,OAAAM,CAAA,CAAAR,GAAA,IAAAQ,CAAA,CAAAK,GAAA,IAAAN,CAAA,CAAAE,CAAA,EAAAP,CAAA,EAAAM,CAAA,IAAAC,CAAA,CAAAP,CAAA,IAAAD,CAAA,CAAAC,CAAA,WAAAO,CAAA,KAAAR,CAAA,EAAAC,CAAA;AAFxB;AAIA;AAAA,IAAAa,QAAA,GAAAlB,OAAA,CAAAc,OAAA,GACeK,mBAAU","ignoreList":[]}
@@ -1,15 +1,15 @@
1
1
  import React, { useState } from 'react';
2
- import { TouchableOpacity, Text, StyleSheet, ActivityIndicator, NativeModules } from 'react-native';
2
+ import { TouchableOpacity, Text, StyleSheet, ActivityIndicator, NativeModules, Alert } from 'react-native';
3
3
  const {
4
- DownloadFile: NativeDownload
4
+ DownloadFileModule
5
5
  } = NativeModules;
6
- const DownloadFile = ({
6
+ export const DownloadFile = ({
7
7
  files,
8
8
  multipleDownload = false,
9
9
  disabled = false,
10
10
  debug = false,
11
11
  maxSize = 0,
12
- fileTypes = ['*/*'],
12
+ fileTypes = [],
13
13
  buttonPlaceHolder = 'Dosyaları İndir',
14
14
  buttonIcon,
15
15
  ButtonStyle,
@@ -18,6 +18,14 @@ const DownloadFile = ({
18
18
  onError
19
19
  }) => {
20
20
  const [isLoading, setIsLoading] = useState(false);
21
+ if (!DownloadFileModule) {
22
+ console.warn("DownloadFileModule bulunamadı. Native tarafın kurulduğundan emin olun.");
23
+ return null;
24
+ }
25
+ const NativeDownloadModuleWrapper = (url, options) => {
26
+ // 🔥 Kotlin Promise metoduyla birebir uyumlu
27
+ return DownloadFileModule.downloadFile(url, options);
28
+ };
21
29
  const handlePress = async () => {
22
30
  if (disabled || isLoading || !files.length) return;
23
31
  setIsLoading(true);
@@ -26,33 +34,57 @@ const DownloadFile = ({
26
34
  maxSize,
27
35
  fileTypes
28
36
  };
29
- const targetFiles = multipleDownload ? files : [files[0]];
37
+
38
+ // ✅ undefined güvenli
39
+ const targetFiles = (multipleDownload ? files : [files[0]]).filter(file => typeof file === 'string' && file.trim().length > 0);
40
+ const sizeErrors = [];
41
+ const typeErrors = [];
42
+ const otherErrors = [];
43
+ const successFiles = [];
30
44
  try {
31
- const promises = targetFiles.map(url => NativeDownload.downloadFile(url, options));
45
+ const promises = targetFiles.map(url => NativeDownloadModuleWrapper(url, options));
32
46
  const results = await Promise.allSettled(promises);
33
- const final = {
34
- successful: [],
35
- skipped: []
36
- };
37
47
  results.forEach((res, index) => {
38
- var _targetFiles$index;
48
+ var _targetFiles$index, _originalUrl$split$po;
39
49
  const originalUrl = (_targetFiles$index = targetFiles[index]) !== null && _targetFiles$index !== void 0 ? _targetFiles$index : "";
50
+ const fileName = ((_originalUrl$split$po = originalUrl.split('/').pop()) === null || _originalUrl$split$po === void 0 ? void 0 : _originalUrl$split$po.split('?')[0]) || `Dosya ${index + 1}`;
40
51
  if (res.status === 'fulfilled') {
41
- final.successful.push({
52
+ successFiles.push({
42
53
  originalUrl,
43
54
  localUri: res.value
44
55
  });
45
56
  } else {
46
- var _res$reason;
47
- final.skipped.push({
48
- originalUrl,
49
- reason: ((_res$reason = res.reason) === null || _res$reason === void 0 ? void 0 : _res$reason.message) || "Bilinmeyen Hata"
50
- });
57
+ var _res$reason, _res$reason2;
58
+ const errorCode = (_res$reason = res.reason) === null || _res$reason === void 0 ? void 0 : _res$reason.code;
59
+ const errorMsg = ((_res$reason2 = res.reason) === null || _res$reason2 === void 0 ? void 0 : _res$reason2.message) || 'Bilinmeyen hata';
60
+ if (errorCode === 'ERR_SIZE_LIMIT') {
61
+ sizeErrors.push(fileName);
62
+ } else if (errorCode === 'ERR_TYPE_MISMATCH') {
63
+ typeErrors.push(fileName);
64
+ } else {
65
+ otherErrors.push(`${fileName}: ${errorMsg}`);
66
+ }
51
67
  }
52
68
  });
53
- if (onSuccess) onSuccess(final);
69
+ if (sizeErrors.length > 0) {
70
+ 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')}`);
71
+ }
72
+ if (typeErrors.length > 0) {
73
+ Alert.alert('Desteklenmeyen Dosya Tipi', `Sadece şu formatlar izin verilmektedir: [${fileTypes.join(', ')}]\n\nUygun olmayan dosyalar:\n\n${typeErrors.join('\n')}`);
74
+ }
75
+ if (otherErrors.length > 0 && debug) {
76
+ Alert.alert('İndirme Hatası', otherErrors.join('\n'));
77
+ }
78
+ const finalResult = {
79
+ successful: successFiles,
80
+ skipped: [...sizeErrors, ...typeErrors, ...otherErrors].map(name => ({
81
+ originalUrl: name,
82
+ reason: 'Failed'
83
+ }))
84
+ };
85
+ onSuccess === null || onSuccess === void 0 || onSuccess(finalResult);
54
86
  } catch (e) {
55
- if (onError) onError(e);else console.error(e);
87
+ onError === null || onError === void 0 || onError(e);
56
88
  } finally {
57
89
  setIsLoading(false);
58
90
  }
@@ -63,7 +95,7 @@ const DownloadFile = ({
63
95
  disabled: disabled || isLoading
64
96
  }, isLoading ? /*#__PURE__*/React.createElement(ActivityIndicator, {
65
97
  color: "#FFF"
66
- }) : buttonIcon ? buttonIcon : /*#__PURE__*/React.createElement(Text, {
98
+ }) : buttonIcon || /*#__PURE__*/React.createElement(Text, {
67
99
  style: [styles.text, ButtonTextStyle]
68
100
  }, buttonPlaceHolder));
69
101
  };
@@ -82,5 +114,4 @@ const styles = StyleSheet.create({
82
114
  backgroundColor: '#AAA'
83
115
  }
84
116
  });
85
- export default DownloadFile;
86
117
  //# sourceMappingURL=DownloadFile.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["React","useState","TouchableOpacity","Text","StyleSheet","ActivityIndicator","NativeModules","DownloadFile","NativeDownload","files","multipleDownload","disabled","debug","maxSize","fileTypes","buttonPlaceHolder","buttonIcon","ButtonStyle","ButtonTextStyle","onSuccess","onError","isLoading","setIsLoading","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","e","console","error","createElement","style","styles","button","onPress","color","text","create","backgroundColor","padding","borderRadius","alignItems","fontWeight"],"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":"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","ignoreList":[]}
1
+ {"version":3,"names":["React","useState","TouchableOpacity","Text","StyleSheet","ActivityIndicator","NativeModules","Alert","DownloadFileModule","DownloadFile","files","multipleDownload","disabled","debug","maxSize","fileTypes","buttonPlaceHolder","buttonIcon","ButtonStyle","ButtonTextStyle","onSuccess","onError","isLoading","setIsLoading","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","join","finalResult","successful","skipped","name","e","createElement","style","styles","button","onPress","color","text","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":[]}
@@ -1 +1 @@
1
- {"version":3,"names":[],"sources":["index.d.ts"],"sourcesContent":["import * as React from 'react';\r\nimport type { DocumentPickerOptions, MyUploaderProps, FileInfo } from './types';\r\n// import type { DownloadFileProps } from './types';\r\n\r\nexport * from './types';\r\n\r\n// DownloadFile Component Tanımı (3. Bunu ekledik)\r\n// export declare const DownloadFile: React.FC<DownloadFileProps>;\r\n\r\n// pickFile Fonksiyon Tanımı\r\nexport declare function pickFile(options?: DocumentPickerOptions): Promise<FileInfo[]>;\r\n\r\nexport declare const MyUploader: React.FC<MyUploaderProps>;\r\n\r\n// Varsayılan dışa aktarım (İsteğe bağlı, genellikle ana bileşen verilir)\r\ndeclare const _default: React.FC<MyUploaderProps>;\r\nexport default _default;"],"mappings":"AAEA;;AAEA,cAAc,SAAS;;AAEvB;AACA;;AAEA;;AAKA;AAAA","ignoreList":[]}
1
+ {"version":3,"names":[],"sources":["index.d.ts"],"sourcesContent":["import * as React from 'react';\r\nimport type { DocumentPickerOptions, MyUploaderProps, FileInfo, DownloadFileProps } from './types';\r\n// import type { DownloadFileProps } from './types';\r\n\r\nexport * from './types';\r\n\r\n// DownloadFile Component Tanımı (3. Bunu ekledik)\r\n// export declare const DownloadFile: React.FC<DownloadFileProps>;\r\n\r\n// pickFile Fonksiyon Tanımı\r\nexport declare function pickFile(options?: DocumentPickerOptions): Promise<FileInfo[]>;\r\nexport declare const DownloadFile :React.FC<DownloadFileProps>;\r\nexport declare const MyUploader: React.FC<MyUploaderProps>;\r\n\r\n// Varsayılan dışa aktarım (İsteğe bağlı, genellikle ana bileşen verilir)\r\ndeclare const _default: React.FC<MyUploaderProps>;\r\nexport default _default;"],"mappings":"AAEA;;AAEA,cAAc,SAAS;;AAEvB;AACA;;AAEA;;AAKA;AAAA","ignoreList":[]}
@@ -1,11 +1,8 @@
1
1
  import MyUploader, { pickFile } from "./components/MyUploader";
2
- // import DownloadFile from "./components/DownloadFile";
3
-
4
- // 2. Diğerlerini NAMED olarak dışa aktar (import { DownloadFile, pickFile } ... için)
5
- // export { DownloadFile, pickFile };
2
+ import { DownloadFile } from "./components/DownloadFile";
6
3
 
7
4
  // Sadece bu paketle ilgili olanları dışa aktar
8
- export { MyUploader, pickFile };
5
+ export { MyUploader, pickFile, DownloadFile };
9
6
  export * from './types';
10
7
 
11
8
  // Varsayılan dışa aktarım olarak da ana bileşeni verelim
@@ -1 +1 @@
1
- {"version":3,"names":["MyUploader","pickFile"],"sources":["index.ts"],"sourcesContent":["import MyUploader,{pickFile} from \"./components/MyUploader\";\r\n// import DownloadFile from \"./components/DownloadFile\";\r\n\r\n// 2. Diğerlerini NAMED olarak dışa aktar (import { DownloadFile, pickFile } ... için)\r\n// export { DownloadFile, pickFile };\r\n\r\n\r\n// Sadece bu paketle ilgili olanları dışa aktar\r\nexport { MyUploader, pickFile };\r\nexport * from './types';\r\n\r\n// Varsayılan dışa aktarım olarak da ana bileşeni verelim\r\nexport default MyUploader;\r\n\r\n\r\n\r\n"],"mappings":"AAAA,OAAOA,UAAU,IAAEC,QAAQ,QAAO,yBAAyB;AAC3D;;AAEA;AACA;;AAGA;AACA,SAASD,UAAU,EAAEC,QAAQ;AAC7B,cAAc,SAAS;;AAEvB;AACA,eAAeD,UAAU","ignoreList":[]}
1
+ {"version":3,"names":["MyUploader","pickFile","DownloadFile"],"sources":["index.ts"],"sourcesContent":["import MyUploader,{pickFile} from \"./components/MyUploader\";\r\nimport {DownloadFile} from \"./components/DownloadFile\";\r\n\r\n\r\n// Sadece bu paketle ilgili olanları dışa aktar\r\nexport { MyUploader, pickFile ,DownloadFile };\r\nexport * from './types';\r\n\r\n// Varsayılan dışa aktarım olarak da ana bileşeni verelim\r\nexport default MyUploader;\r\n\r\n\r\n\r\n"],"mappings":"AAAA,OAAOA,UAAU,IAAEC,QAAQ,QAAO,yBAAyB;AAC3D,SAAQC,YAAY,QAAO,2BAA2B;;AAGtD;AACA,SAASF,UAAU,EAAEC,QAAQ,EAAEC,YAAY;AAC3C,cAAc,SAAS;;AAEvB;AACA,eAAeF,UAAU","ignoreList":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-my-uploader-android",
3
- "version": "1.0.32",
3
+ "version": "1.0.37",
4
4
  "description": "file uploader for android",
5
5
  "main": "./lib/module/index.js",
6
6
  "types": "./src/index.d.ts",
@@ -1,18 +1,23 @@
1
1
  import React, { useState } from 'react';
2
- import { TouchableOpacity, Text, StyleSheet, ActivityIndicator,NativeModules } from 'react-native';
2
+ import {
3
+ TouchableOpacity,
4
+ Text,
5
+ StyleSheet,
6
+ ActivityIndicator,
7
+ NativeModules,
8
+ Alert,
9
+ } from 'react-native';
3
10
  import type { DownloadFileProps, DownloadResult } from '../types';
4
11
 
12
+ const { DownloadFileModule } = NativeModules;
5
13
 
6
- const { DownloadFile: NativeDownload } = NativeModules;
7
-
8
-
9
- const DownloadFile: React.FC<DownloadFileProps> = ({
14
+ export const DownloadFile: React.FC<DownloadFileProps> = ({
10
15
  files,
11
16
  multipleDownload = false,
12
17
  disabled = false,
13
18
  debug = false,
14
19
  maxSize = 0,
15
- fileTypes = ['*/*'],
20
+ fileTypes = [],
16
21
  buttonPlaceHolder = 'Dosyaları İndir',
17
22
  buttonIcon,
18
23
  ButtonStyle,
@@ -22,35 +27,102 @@ const DownloadFile: React.FC<DownloadFileProps> = ({
22
27
  }) => {
23
28
  const [isLoading, setIsLoading] = useState(false);
24
29
 
30
+ if (!DownloadFileModule) {
31
+ console.warn("DownloadFileModule bulunamadı. Native tarafın kurulduğundan emin olun.");
32
+ return null;
33
+ }
34
+
35
+ const NativeDownloadModuleWrapper = (
36
+ url: string,
37
+ options: any
38
+ ): Promise<string> => {
39
+ // 🔥 Kotlin Promise metoduyla birebir uyumlu
40
+ return DownloadFileModule.downloadFile(url, options);
41
+ };
42
+
25
43
  const handlePress = async () => {
26
44
  if (disabled || isLoading || !files.length) return;
27
45
  setIsLoading(true);
28
46
 
29
47
  const options = { debug, maxSize, fileTypes };
30
- const targetFiles = multipleDownload ? files : [files[0]];
48
+
49
+ // ✅ undefined güvenli
50
+ const targetFiles: string[] = (
51
+ multipleDownload ? files : [files[0]]
52
+ ).filter((file): file is string => typeof file === 'string' && file.trim().length > 0);
53
+
54
+ const sizeErrors: string[] = [];
55
+ const typeErrors: string[] = [];
56
+ const otherErrors: string[] = [];
57
+ const successFiles: DownloadResult['successful'] = [];
31
58
 
32
59
  try {
33
- const promises = targetFiles.map(url => NativeDownload.downloadFile(url, options));
60
+ const promises = targetFiles.map(url =>
61
+ NativeDownloadModuleWrapper(url, options)
62
+ );
63
+
34
64
  const results = await Promise.allSettled(promises);
35
-
36
- const final: DownloadResult = { successful: [], skipped: [] };
37
65
 
38
66
  results.forEach((res, index) => {
39
67
  const originalUrl = targetFiles[index] ?? "";
68
+ const fileName =
69
+ originalUrl.split('/').pop()?.split('?')[0] ||
70
+ `Dosya ${index + 1}`;
71
+
40
72
  if (res.status === 'fulfilled') {
41
- final.successful.push({ originalUrl, localUri: res.value });
42
- } else {
43
- final.skipped.push({
44
- originalUrl,
45
- reason: res.reason?.message || "Bilinmeyen Hata"
73
+ successFiles.push({
74
+ originalUrl,
75
+ localUri: res.value,
46
76
  });
77
+ } else {
78
+ const errorCode = res.reason?.code;
79
+ const errorMsg = res.reason?.message || 'Bilinmeyen hata';
80
+
81
+ if (errorCode === 'ERR_SIZE_LIMIT') {
82
+ sizeErrors.push(fileName);
83
+ } else if (errorCode === 'ERR_TYPE_MISMATCH') {
84
+ typeErrors.push(fileName);
85
+ } else {
86
+ otherErrors.push(`${fileName}: ${errorMsg}`);
87
+ }
47
88
  }
48
89
  });
49
90
 
50
- if (onSuccess) onSuccess(final);
91
+ if (sizeErrors.length > 0) {
92
+ Alert.alert(
93
+ 'Boyut Sınırı Aşıldı',
94
+ `Aşağıdaki dosyalar ${maxSize}MB sınırını aştığı için indirilemedi:\n\n${sizeErrors.join(
95
+ '\n'
96
+ )}`
97
+ );
98
+ }
99
+
100
+ if (typeErrors.length > 0) {
101
+ Alert.alert(
102
+ 'Desteklenmeyen Dosya Tipi',
103
+ `Sadece şu formatlar izin verilmektedir: [${fileTypes.join(
104
+ ', '
105
+ )}]\n\nUygun olmayan dosyalar:\n\n${typeErrors.join('\n')}`
106
+ );
107
+ }
108
+
109
+ if (otherErrors.length > 0 && debug) {
110
+ Alert.alert('İndirme Hatası', otherErrors.join('\n'));
111
+ }
112
+
113
+ const finalResult: DownloadResult = {
114
+ successful: successFiles,
115
+ skipped: [...sizeErrors, ...typeErrors, ...otherErrors].map(
116
+ name => ({
117
+ originalUrl: name,
118
+ reason: 'Failed',
119
+ })
120
+ ),
121
+ };
122
+
123
+ onSuccess?.(finalResult);
51
124
  } catch (e) {
52
- if (onError) onError(e);
53
- else console.error(e);
125
+ onError?.(e);
54
126
  } finally {
55
127
  setIsLoading(false);
56
128
  }
@@ -65,7 +137,11 @@ const DownloadFile: React.FC<DownloadFileProps> = ({
65
137
  {isLoading ? (
66
138
  <ActivityIndicator color="#FFF" />
67
139
  ) : (
68
- buttonIcon ? buttonIcon : <Text style={[styles.text, ButtonTextStyle]}>{buttonPlaceHolder}</Text>
140
+ buttonIcon || (
141
+ <Text style={[styles.text, ButtonTextStyle]}>
142
+ {buttonPlaceHolder}
143
+ </Text>
144
+ )
69
145
  )}
70
146
  </TouchableOpacity>
71
147
  );
@@ -78,8 +154,12 @@ const styles = StyleSheet.create({
78
154
  borderRadius: 8,
79
155
  alignItems: 'center',
80
156
  },
81
- text: { color: '#000', fontWeight: 'bold' },
82
- disabled: { backgroundColor: '#AAA' }
157
+ text: {
158
+ color: '#000',
159
+ fontWeight: 'bold',
160
+ },
161
+ disabled: {
162
+ backgroundColor: '#AAA',
163
+ },
83
164
  });
84
165
 
85
- export default DownloadFile;
package/src/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as React from 'react';
2
- import type { DocumentPickerOptions, MyUploaderProps, FileInfo } from './types';
2
+ import type { DocumentPickerOptions, MyUploaderProps, FileInfo, DownloadFileProps } from './types';
3
3
  // import type { DownloadFileProps } from './types';
4
4
 
5
5
  export * from './types';
@@ -9,7 +9,7 @@ export * from './types';
9
9
 
10
10
  // pickFile Fonksiyon Tanımı
11
11
  export declare function pickFile(options?: DocumentPickerOptions): Promise<FileInfo[]>;
12
-
12
+ export declare const DownloadFile :React.FC<DownloadFileProps>;
13
13
  export declare const MyUploader: React.FC<MyUploaderProps>;
14
14
 
15
15
  // Varsayılan dışa aktarım (İsteğe bağlı, genellikle ana bileşen verilir)
package/src/index.ts CHANGED
@@ -1,12 +1,9 @@
1
1
  import MyUploader,{pickFile} from "./components/MyUploader";
2
- // import DownloadFile from "./components/DownloadFile";
3
-
4
- // 2. Diğerlerini NAMED olarak dışa aktar (import { DownloadFile, pickFile } ... için)
5
- // export { DownloadFile, pickFile };
2
+ import {DownloadFile} from "./components/DownloadFile";
6
3
 
7
4
 
8
5
  // Sadece bu paketle ilgili olanları dışa aktar
9
- export { MyUploader, pickFile };
6
+ export { MyUploader, pickFile ,DownloadFile };
10
7
  export * from './types';
11
8
 
12
9
  // Varsayılan dışa aktarım olarak da ana bileşeni verelim