@@ -33,6 +33,7 @@ public class RNFetchBlobFileResp extends ResponseBody {
3333 long bytesDownloaded = 0 ;
3434 ReactApplicationContext rctContext ;
3535 FileOutputStream ofStream ;
36+ boolean isEndMarkerReceived ;
3637
3738 public RNFetchBlobFileResp (ReactApplicationContext ctx , String taskId , ResponseBody body , String path , boolean overwrite ) throws IOException {
3839 super ();
@@ -41,6 +42,7 @@ public RNFetchBlobFileResp(ReactApplicationContext ctx, String taskId, ResponseB
4142 this .originalBody = body ;
4243 assert path != null ;
4344 this .mPath = path ;
45+ this .isEndMarkerReceived = false ;
4446 if (path != null ) {
4547 boolean appendToExistingFile = !overwrite ;
4648 path = path .replace ("?append=true" , "" );
@@ -68,6 +70,11 @@ public long contentLength() {
6870 return originalBody .contentLength ();
6971 }
7072
73+ public boolean isDownloadComplete () {
74+ return (bytesDownloaded == contentLength ()) // Case of non-chunked downloads
75+ || (contentLength () == -1 && isEndMarkerReceived ); // Case of chunked downloads
76+ }
77+
7178 @ Override
7279 public BufferedSource source () {
7380 ProgressReportingSource countable = new ProgressReportingSource ();
@@ -83,22 +90,49 @@ public long read(@NonNull Buffer sink, long byteCount) throws IOException {
8390 bytesDownloaded += read > 0 ? read : 0 ;
8491 if (read > 0 ) {
8592 ofStream .write (bytes , 0 , (int ) read );
93+ } else if (contentLength () == -1 && read == -1 ) {
94+ // End marker has been received for chunked download
95+ isEndMarkerReceived = true ;
8696 }
8797 RNFetchBlobProgressConfig reportConfig = RNFetchBlobReq .getReportProgress (mTaskId );
88- if (reportConfig != null && contentLength () != 0 &&reportConfig .shouldReport (bytesDownloaded / contentLength ())) {
89- WritableMap args = Arguments .createMap ();
90- args .putString ("taskId" , mTaskId );
91- args .putString ("written" , String .valueOf (bytesDownloaded ));
92- args .putString ("total" , String .valueOf (contentLength ()));
93- rctContext .getJSModule (DeviceEventManagerModule .RCTDeviceEventEmitter .class )
94- .emit (RNFetchBlobConst .EVENT_PROGRESS , args );
98+
99+ if (contentLength () != 0 ) {
100+
101+ // For non-chunked download, progress is received / total
102+ // For chunked download, progress can be either 0 (started) or 1 (ended)
103+ float progress = (contentLength () != -1 ) ? bytesDownloaded / contentLength () : ( ( isEndMarkerReceived ) ? 1 : 0 );
104+
105+ if (reportConfig != null && reportConfig .shouldReport (progress /* progress */ )) {
106+ if (contentLength () != -1 ) {
107+ // For non-chunked downloads
108+ reportProgress (mTaskId , bytesDownloaded , contentLength ());
109+ } else {
110+ // For chunked downloads
111+ if (!isEndMarkerReceived ) {
112+ reportProgress (mTaskId , 0 , contentLength ());
113+ } else {
114+ reportProgress (mTaskId , bytesDownloaded , bytesDownloaded );
115+ }
116+ }
117+ }
118+
95119 }
120+
96121 return read ;
97122 } catch (Exception ex ) {
98123 return -1 ;
99124 }
100125 }
101126
127+ private void reportProgress (String taskId , long bytesDownloaded , long contentLength ) {
128+ WritableMap args = Arguments .createMap ();
129+ args .putString ("taskId" , taskId );
130+ args .putString ("written" , String .valueOf (bytesDownloaded ));
131+ args .putString ("total" , String .valueOf (contentLength ));
132+ rctContext .getJSModule (DeviceEventManagerModule .RCTDeviceEventEmitter .class )
133+ .emit (RNFetchBlobConst .EVENT_PROGRESS , args );
134+ }
135+
102136 @ Override
103137 public Timeout timeout () {
104138 return null ;
0 commit comments