From 26fa302b0fd9b5dc7a984362536e0bfbe675c37f Mon Sep 17 00:00:00 2001 From: Rene Floor Date: Fri, 20 Mar 2020 15:04:27 +0100 Subject: [PATCH 1/2] Moved web files to separate folder --- lib/flutter_cache_manager.dart | 4 ++-- lib/src/cache_manager.dart | 4 ++-- lib/src/{ => web}/file_fetcher.dart | 3 +-- lib/src/{ => web}/web_helper.dart | 2 +- 4 files changed, 6 insertions(+), 7 deletions(-) rename lib/src/{ => web}/file_fetcher.dart (97%) rename lib/src/{ => web}/web_helper.dart (98%) diff --git a/lib/flutter_cache_manager.dart b/lib/flutter_cache_manager.dart index ea3bd256..bd88d923 100644 --- a/lib/flutter_cache_manager.dart +++ b/lib/flutter_cache_manager.dart @@ -1,4 +1,4 @@ export 'src/cache_manager.dart'; -export 'src/file_fetcher.dart'; +export 'src/web/file_fetcher.dart'; export 'src/file_info.dart'; -export 'src/web_helper.dart' show HttpExceptionWithStatus; +export 'src/web/web_helper.dart' show HttpExceptionWithStatus; diff --git a/lib/src/cache_manager.dart b/lib/src/cache_manager.dart index 071700d2..faf2bc55 100644 --- a/lib/src/cache_manager.dart +++ b/lib/src/cache_manager.dart @@ -6,9 +6,9 @@ import 'package:file/file.dart' as f; import 'package:file/local.dart'; import 'package:flutter_cache_manager/src/storage/cache_object.dart'; import 'package:flutter_cache_manager/src/cache_store.dart'; -import 'package:flutter_cache_manager/src/file_fetcher.dart'; +import 'package:flutter_cache_manager/src/web/file_fetcher.dart'; import 'package:flutter_cache_manager/src/file_info.dart'; -import 'package:flutter_cache_manager/src/web_helper.dart'; +import 'package:flutter_cache_manager/src/web/web_helper.dart'; import 'package:path/path.dart' as p; import 'package:path_provider/path_provider.dart'; import 'package:pedantic/pedantic.dart'; diff --git a/lib/src/file_fetcher.dart b/lib/src/web/file_fetcher.dart similarity index 97% rename from lib/src/file_fetcher.dart rename to lib/src/web/file_fetcher.dart index f8d89d89..029ab146 100644 --- a/lib/src/file_fetcher.dart +++ b/lib/src/web/file_fetcher.dart @@ -1,6 +1,5 @@ import 'dart:async'; import 'package:clock/clock.dart'; -import 'package:flutter_cache_manager/src/web_helper.dart'; import 'package:http/http.dart' as http; ///Flutter Cache Manager @@ -37,7 +36,7 @@ class HttpFileFetcher implements FileService { /// Defines the interface for a get result of a [FileService]. abstract class FileFetcherResponse { /// [content] is a stream of bytes - Stream> get content => null; + Stream> get content; /// [statusCode] is expected to conform to an http status code. int get statusCode; /// Defines till when the cache should be assumed to be valid. diff --git a/lib/src/web_helper.dart b/lib/src/web/web_helper.dart similarity index 98% rename from lib/src/web_helper.dart rename to lib/src/web/web_helper.dart index 25a19c2b..22132be4 100644 --- a/lib/src/web_helper.dart +++ b/lib/src/web/web_helper.dart @@ -3,7 +3,7 @@ import 'dart:io'; import 'package:flutter_cache_manager/src/storage/cache_object.dart'; import 'package:flutter_cache_manager/src/cache_store.dart'; -import 'package:flutter_cache_manager/src/file_fetcher.dart'; +import 'package:flutter_cache_manager/src/web/file_fetcher.dart'; import 'package:flutter_cache_manager/src/file_info.dart'; import 'package:pedantic/pedantic.dart'; import 'package:uuid/uuid.dart'; From 3fd1b7c09a29cf3d9efa84cf51f1af7398fe8370 Mon Sep 17 00:00:00 2001 From: Rene Floor Date: Fri, 20 Mar 2020 15:41:32 +0100 Subject: [PATCH 2/2] support most --- analysis_options.yaml | 2 + lib/flutter_cache_manager.dart | 2 +- lib/src/cache_manager.dart | 1 + lib/src/web/file_fetcher.dart | 14 +++-- lib/src/web/mime_converter.dart | 90 ++++++++++++++++++++++++++++++++ pubspec.yaml | 2 +- test/http_file_fetcher_test.dart | 4 +- 7 files changed, 106 insertions(+), 9 deletions(-) create mode 100644 lib/src/web/mime_converter.dart diff --git a/analysis_options.yaml b/analysis_options.yaml index 79736a91..ca9505c9 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -9,6 +9,8 @@ analyzer: unused_local_variable: warning dead_code: warning invalid_override_of_non_virtual_member: error + enable-experiment: + - extension-methods linter: rules: diff --git a/lib/flutter_cache_manager.dart b/lib/flutter_cache_manager.dart index bd88d923..8d7e6f28 100644 --- a/lib/flutter_cache_manager.dart +++ b/lib/flutter_cache_manager.dart @@ -1,4 +1,4 @@ export 'src/cache_manager.dart'; -export 'src/web/file_fetcher.dart'; export 'src/file_info.dart'; +export 'src/web/file_fetcher.dart'; export 'src/web/web_helper.dart' show HttpExceptionWithStatus; diff --git a/lib/src/cache_manager.dart b/lib/src/cache_manager.dart index faf2bc55..d0926b2e 100644 --- a/lib/src/cache_manager.dart +++ b/lib/src/cache_manager.dart @@ -4,6 +4,7 @@ import 'dart:typed_data'; import 'package:file/file.dart' as f; import 'package:file/local.dart'; +import 'package:flutter/material.dart'; import 'package:flutter_cache_manager/src/storage/cache_object.dart'; import 'package:flutter_cache_manager/src/cache_store.dart'; import 'package:flutter_cache_manager/src/web/file_fetcher.dart'; diff --git a/lib/src/web/file_fetcher.dart b/lib/src/web/file_fetcher.dart index 029ab146..cd942e07 100644 --- a/lib/src/web/file_fetcher.dart +++ b/lib/src/web/file_fetcher.dart @@ -1,6 +1,8 @@ import 'dart:async'; +import 'dart:io'; import 'package:clock/clock.dart'; import 'package:http/http.dart' as http; +import 'mime_converter.dart'; ///Flutter Cache Manager ///Copyright (c) 2019 Rene Floor @@ -18,7 +20,7 @@ abstract class FileService { /// [WebHelper]. One can easily adapt it to use dio or any other http client. class HttpFileFetcher implements FileService { http.Client _httpClient; - HttpFileFetcher({http.Client httpClient}){ + HttpFileFetcher({http.Client httpClient}) { _httpClient = httpClient ?? http.Client(); } @@ -37,12 +39,16 @@ class HttpFileFetcher implements FileService { abstract class FileFetcherResponse { /// [content] is a stream of bytes Stream> get content; + /// [statusCode] is expected to conform to an http status code. int get statusCode; + /// Defines till when the cache should be assumed to be valid. DateTime get validTill; + /// [eTag] is used when asking to update the cache String get eTag; + /// Used to save the file on the storage, includes a dot. For example '.jpeg' String get fileExtension; } @@ -99,10 +105,8 @@ class HttpFileFetcherResponse implements FileFetcherResponse { String get fileExtension { var fileExtension = ''; if (_hasHeader('content-type')) { - final type = _header('content-type').split('/'); - if (type.length == 2) { - fileExtension = '.${type[1]}'; - } + var contentType = ContentType.parse(_header('content-type')); + fileExtension = contentType.fileExtension ?? ''; } return fileExtension; } diff --git a/lib/src/web/mime_converter.dart b/lib/src/web/mime_converter.dart new file mode 100644 index 00000000..ddab2900 --- /dev/null +++ b/lib/src/web/mime_converter.dart @@ -0,0 +1,90 @@ +import 'dart:io'; + +///Converts the most common MIME types to the most expected file extension. +extension ContentTypeConverter on ContentType { + String get fileExtension { + if (this == null) return null; + if (mimeTypes.containsKey(toString())) return mimeTypes[toString()]; + return '.$subType'; + } +} + +/// Source of MIME Types: +/// https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types +/// Updated on 20th of March in 2020 while being quarantined +const mimeTypes = { + 'application/epub+zip': '.epub', + 'application/gzip': '.gz', + 'application/java-archive': '.jar', + 'application/json': '.json', + 'application/ld+json': '.jsonld', + 'application/msword': '.doc', + 'application/octet-stream': '.bin', + 'application/ogg': '.ogx', + 'application/pdf': '.pdf', + 'application/php': '.php', + 'application/rtf': '.rtf', + 'application/vnd.amazon.ebook': '.azw', + 'application/vnd.apple.installer+xml': '.mpkg', + 'application/vnd.mozilla.xul+xml': '.xul', + 'application/vnd.ms-excel': '.xls', + 'application/vnd.ms-fontobject': '.eot', + 'application/vnd.ms-powerpoint': '.ppt', + 'application/vnd.oasis.opendocument.presentation': '.odp', + 'application/vnd.oasis.opendocument.spreadsheet': '.ods', + 'application/vnd.oasis.opendocument.text': '.odt', + 'application/vnd.openxmlformats-officedocument.presentationml.presentation': + '.pptx', + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': '.xlsx', + 'application/vnd.openxmlformats-officedocument.wordprocessingml.document': + '.docx', + 'application/vnd.rar': '.rar', + 'application/vnd.visio': '.vsd', + 'application/x-7z-compressed': '.7z', + 'application/x-abiword': '.abw', + 'application/x-bzip': '.bz', + 'application/x-bzip2': '.bz2', + 'application/x-csh': '.csh', + 'application/x-freearc': '.arc', + 'application/x-sh': '.sh', + 'application/x-shockwave-flash': '.swf', + 'application/x-tar': '.tar', + 'application/xhtml+xml': '.xhtml', + 'application/xml': '.xml', + 'application/zip': '.zip', + 'audio/3gpp': '.3gp', + 'audio/3gpp2': '.3g2', + 'audio/aac': '.aac', + 'audio/midi audio/x-midi': '.midi', + 'audio/mpeg': '.mp3', + 'audio/ogg': '.oga', + 'audio/opus': '.opus', + 'audio/wav': '.wav', + 'audio/webm': '.weba', + 'font/otf': '.otf', + 'font/ttf': '.ttf', + 'font/woff': '.woff', + 'font/woff2': '.woff2', + 'image/bmp': '.bmp', + 'image/gif': '.gif', + 'image/jpeg': '.jpg', + 'image/png': '.png', + 'image/svg+xml': '.svg', + 'image/tiff': '.tiff', + 'image/vnd.microsoft.icon': '.ico', + 'image/webp': '.webp', + 'text/calendar': '.ics', + 'text/css': '.css', + 'text/csv': '.csv', + 'text/html': '.html', + 'text/javascript': '.js', + 'text/plain': '.txt', + 'text/xml': '.xml', + 'video/3gpp': '.3gp', + 'video/3gpp2': '.3g2', + 'video/mp2t': '.ts', + 'video/mpeg': '.mpeg', + 'video/ogg': '.ogv', + 'video/webm': '.webm', + 'video/x-msvideo': '.avi' +}; diff --git a/pubspec.yaml b/pubspec.yaml index 4f6a1109..90c0e865 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -5,7 +5,7 @@ author: Rene Floor homepage: https://github.com/renefloor/flutter_cache_manager environment: - sdk: ">=2.1.0 <3.0.0" + sdk: ">=2.6.0 <3.0.0" dependencies: flutter: diff --git a/test/http_file_fetcher_test.dart b/test/http_file_fetcher_test.dart index e6cf2cb2..f660b83c 100644 --- a/test/http_file_fetcher_test.dart +++ b/test/http_file_fetcher_test.dart @@ -10,8 +10,8 @@ void main() { group('Check header values', () { test('Valid headers should be parsed normally', () async { var eTag = 'test'; - var fileExtension = 'jpeg'; - var contentType = 'image/$fileExtension'; + var fileExtension = 'jpg'; + var contentType = 'image/jpeg'; var maxAge = const Duration(hours: 2); var client = MockClient((request) async {