Handle offline upload fallback as deferred pending state
This commit is contained in:
@@ -143,6 +143,8 @@ class _UploadPageState extends State<UploadPage> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _uploadAll() async {
|
Future<void> _uploadAll() async {
|
||||||
|
var deferredCount = 0;
|
||||||
|
var failedCount = 0;
|
||||||
for (final item in _photos.where((i) => i.status == UploadStatus.pending)) {
|
for (final item in _photos.where((i) => i.status == UploadStatus.pending)) {
|
||||||
setState(() => item.status = UploadStatus.uploading);
|
setState(() => item.status = UploadStatus.uploading);
|
||||||
try {
|
try {
|
||||||
@@ -152,10 +154,32 @@ class _UploadPageState extends State<UploadPage> {
|
|||||||
? UploadStatus.done
|
? UploadStatus.done
|
||||||
: UploadStatus.failed;
|
: UploadStatus.failed;
|
||||||
});
|
});
|
||||||
} catch (_) {
|
if (res.statusCode != 200) {
|
||||||
setState(() => item.status = UploadStatus.failed);
|
failedCount++;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
if (_isNetworkError(e)) {
|
||||||
|
setState(() => item.status = UploadStatus.pending);
|
||||||
|
deferredCount++;
|
||||||
|
} else {
|
||||||
|
setState(() => item.status = UploadStatus.failed);
|
||||||
|
failedCount++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (mounted && deferredCount > 0) {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(
|
||||||
|
content: Text(
|
||||||
|
'$deferredCount upload(s) deferred: network unavailable. Try again when connection is back.',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else if (mounted && failedCount > 0) {
|
||||||
|
ScaffoldMessenger.of(
|
||||||
|
context,
|
||||||
|
).showSnackBar(SnackBar(content: Text('$failedCount upload(s) failed.')));
|
||||||
|
}
|
||||||
await _loadGallery();
|
await _loadGallery();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -213,7 +237,7 @@ class _UploadPageState extends State<UploadPage> {
|
|||||||
req.headers['Authorization'] = 'Bearer $token';
|
req.headers['Authorization'] = 'Bearer $token';
|
||||||
req.files.add(await http.MultipartFile.fromPath('file', file.path));
|
req.files.add(await http.MultipartFile.fromPath('file', file.path));
|
||||||
req.fields['filename'] = p.basename(file.path);
|
req.fields['filename'] = p.basename(file.path);
|
||||||
return await req.send();
|
return await req.send().timeout(const Duration(seconds: 4));
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -226,7 +250,14 @@ class _UploadPageState extends State<UploadPage> {
|
|||||||
Uri.parse('$brokerUrl/upload/$filename'),
|
Uri.parse('$brokerUrl/upload/$filename'),
|
||||||
);
|
);
|
||||||
req.files.add(await http.MultipartFile.fromPath('file', file.path));
|
req.files.add(await http.MultipartFile.fromPath('file', file.path));
|
||||||
return req.send();
|
return req.send().timeout(const Duration(seconds: 20));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _isNetworkError(Object error) {
|
||||||
|
return error is SocketException ||
|
||||||
|
error is TimeoutException ||
|
||||||
|
error is HttpException ||
|
||||||
|
error is http.ClientException;
|
||||||
}
|
}
|
||||||
|
|
||||||
Uri? _normalizeDirectEndpoint(String value) {
|
Uri? _normalizeDirectEndpoint(String value) {
|
||||||
|
|||||||
Reference in New Issue
Block a user