@@ -33,6 +33,7 @@ public class RNFetchBlobFileResp extends ResponseBody {
33
33
long bytesDownloaded = 0 ;
34
34
ReactApplicationContext rctContext ;
35
35
FileOutputStream ofStream ;
36
+ boolean isEndMarkerReceived ;
36
37
37
38
public RNFetchBlobFileResp (ReactApplicationContext ctx , String taskId , ResponseBody body , String path , boolean overwrite ) throws IOException {
38
39
super ();
@@ -41,6 +42,7 @@ public RNFetchBlobFileResp(ReactApplicationContext ctx, String taskId, ResponseB
41
42
this .originalBody = body ;
42
43
assert path != null ;
43
44
this .mPath = path ;
45
+ this .isEndMarkerReceived = false ;
44
46
if (path != null ) {
45
47
boolean appendToExistingFile = !overwrite ;
46
48
path = path .replace ("?append=true" , "" );
@@ -68,6 +70,11 @@ public long contentLength() {
68
70
return originalBody .contentLength ();
69
71
}
70
72
73
+ public boolean isDownloadComplete () {
74
+ return (bytesDownloaded == contentLength ()) // Case of non-chunked downloads
75
+ || (contentLength () == -1 && isEndMarkerReceived ); // Case of chunked downloads
76
+ }
77
+
71
78
@ Override
72
79
public BufferedSource source () {
73
80
ProgressReportingSource countable = new ProgressReportingSource ();
@@ -83,22 +90,49 @@ public long read(@NonNull Buffer sink, long byteCount) throws IOException {
83
90
bytesDownloaded += read > 0 ? read : 0 ;
84
91
if (read > 0 ) {
85
92
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 ;
86
96
}
87
97
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
+
95
119
}
120
+
96
121
return read ;
97
122
} catch (Exception ex ) {
98
123
return -1 ;
99
124
}
100
125
}
101
126
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
+
102
136
@ Override
103
137
public Timeout timeout () {
104
138
return null ;
0 commit comments