This repository was archived by the owner on Feb 22, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 9.8k
[cross_file] An abstraction to allow working with files across multiple platforms. #3260
Merged
Merged
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
003752f
Initial version of x_file package
mvanbeusekom ff1be08
Renamed from x_file to cross_file
mvanbeusekom 8202c5b
Add back x_file type to file_selector
mvanbeusekom c06be6b
Fix formatting issues
mvanbeusekom 0276a94
Update homepage and version
mvanbeusekom ccc9338
Added README.md
mvanbeusekom 67ee328
Added missing copyright
mvanbeusekom 01fe65e
Revert "Added missing copyright"
mvanbeusekom 6cb6b98
Add missing copyright
mvanbeusekom 02e7df1
Renamed class implementation back to XFile
mvanbeusekom f6ab812
Fix formatting issues
mvanbeusekom eadc0b0
Rename to cross_file
mvanbeusekom 481867c
Added code owners for cross_file package
mvanbeusekom File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
## 0.1.0 | ||
|
||
- Initial open-source release |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
Copyright 2020 The Flutter Authors. All rights reserved. | ||
|
||
Redistribution and use in source and binary forms, with or without modification, | ||
are permitted provided that the following conditions are met: | ||
|
||
* Redistributions of source code must retain the above copyright | ||
notice, this list of conditions and the following disclaimer. | ||
* Redistributions in binary form must reproduce the above | ||
copyright notice, this list of conditions and the following | ||
disclaimer in the documentation and/or other materials provided | ||
with the distribution. | ||
* Neither the name of Google Inc. nor the names of its | ||
contributors may be used to endorse or promote products derived | ||
from this software without specific prior written permission. | ||
|
||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | ||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR | ||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | ||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
# cross_file | ||
|
||
An abstraction to allow working with files across multiple platforms. | ||
|
||
# Usage | ||
|
||
Import `package:cross/cross_info.dart`, instantiate a `CrossFile` | ||
using a path or byte array and use its methods and properties to | ||
access the file and its metadata. | ||
|
||
Example: | ||
|
||
```dart | ||
import 'package:cross_file/cross_file.dart'; | ||
|
||
final file = CrossFile('assets/hello.txt'); | ||
|
||
print('File information:'); | ||
print('- Path: ${file.path}'); | ||
print('- Name: ${file.name}'); | ||
print('- MIME type: ${file.mimeType}'); | ||
|
||
final fileContent = await file.readAsString(); | ||
print('Content of the file: ${fileContent}'); // e.g. "Moto G (4)" | ||
``` | ||
|
||
You will find links to the API docs on the [pub page](https://pub.dartlang.org/packages/cross_file). | ||
|
||
## Getting Started | ||
|
||
For help getting started with Flutter, view our online | ||
[documentation](http://flutter.io/). | ||
|
||
For help on editing plugin code, view the [documentation](https://flutter.io/platform-plugins/#edit-code). |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
// Copyright 2018 The Chromium Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
export 'src/x_file.dart'; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
// Copyright 2018 The Chromium Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
import 'dart:convert'; | ||
import 'dart:typed_data'; | ||
|
||
/// The interface for a CrossFile. | ||
/// | ||
/// A CrossFile is a container that wraps the path of a selected | ||
/// file by the user and (in some platforms, like web) the bytes | ||
/// with the contents of the file. | ||
/// | ||
/// This class is a very limited subset of dart:io [File], so all | ||
/// the methods should seem familiar. | ||
abstract class XFileBase { | ||
/// Construct a CrossFile | ||
XFileBase(String path); | ||
|
||
/// Save the CrossFile at the indicated file path. | ||
void saveTo(String path) async { | ||
throw UnimplementedError('saveTo has not been implemented.'); | ||
} | ||
|
||
/// Get the path of the picked file. | ||
/// | ||
/// This should only be used as a backwards-compatibility clutch | ||
/// for mobile apps, or cosmetic reasons only (to show the user | ||
/// the path they've picked). | ||
/// | ||
/// Accessing the data contained in the picked file by its path | ||
/// is platform-dependant (and won't work on web), so use the | ||
/// byte getters in the CrossFile instance instead. | ||
String get path { | ||
throw UnimplementedError('.path has not been implemented.'); | ||
} | ||
|
||
/// The name of the file as it was selected by the user in their device. | ||
/// | ||
/// Use only for cosmetic reasons, do not try to use this as a path. | ||
String get name { | ||
throw UnimplementedError('.name has not been implemented.'); | ||
} | ||
|
||
/// For web, it may be necessary for a file to know its MIME type. | ||
String get mimeType { | ||
throw UnimplementedError('.mimeType has not been implemented.'); | ||
} | ||
|
||
/// Get the length of the file. Returns a `Future<int>` that completes with the length in bytes. | ||
Future<int> length() { | ||
throw UnimplementedError('.length() has not been implemented.'); | ||
} | ||
|
||
/// Synchronously read the entire file contents as a string using the given [Encoding]. | ||
/// | ||
/// By default, `encoding` is [utf8]. | ||
/// | ||
/// Throws Exception if the operation fails. | ||
Future<String> readAsString({Encoding encoding = utf8}) { | ||
throw UnimplementedError('readAsString() has not been implemented.'); | ||
} | ||
|
||
/// Synchronously read the entire file contents as a list of bytes. | ||
/// | ||
/// Throws Exception if the operation fails. | ||
Future<Uint8List> readAsBytes() { | ||
throw UnimplementedError('readAsBytes() has not been implemented.'); | ||
} | ||
|
||
/// Create a new independent [Stream] for the contents of this file. | ||
/// | ||
/// If `start` is present, the file will be read from byte-offset `start`. Otherwise from the beginning (index 0). | ||
/// | ||
/// If `end` is present, only up to byte-index `end` will be read. Otherwise, until end of file. | ||
/// | ||
/// In order to make sure that system resources are freed, the stream must be read to completion or the subscription on the stream must be cancelled. | ||
Stream<Uint8List> openRead([int start, int end]) { | ||
throw UnimplementedError('openRead() has not been implemented.'); | ||
} | ||
|
||
/// Get the last-modified time for the CrossFile | ||
Future<DateTime> lastModified() { | ||
throw UnimplementedError('openRead() has not been implemented.'); | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
// Copyright 2018 The Chromium Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
import 'dart:convert'; | ||
ditman marked this conversation as resolved.
Show resolved
Hide resolved
|
||
import 'dart:typed_data'; | ||
|
||
import 'package:http/http.dart' as http show readBytes; | ||
import 'package:meta/meta.dart'; | ||
import 'dart:html'; | ||
|
||
import '../web_helpers/web_helpers.dart'; | ||
import './base.dart'; | ||
|
||
/// A CrossFile that works on web. | ||
/// | ||
/// It wraps the bytes of a selected file. | ||
class XFile extends XFileBase { | ||
String path; | ||
|
||
final String mimeType; | ||
final Uint8List _data; | ||
final int _length; | ||
final String name; | ||
final DateTime _lastModified; | ||
Element _target; | ||
|
||
final CrossFileTestOverrides _overrides; | ||
|
||
bool get _hasTestOverrides => _overrides != null; | ||
|
||
/// Construct a CrossFile object from its ObjectUrl. | ||
/// | ||
/// Optionally, this can be initialized with `bytes` and `length` | ||
/// so no http requests are performed to retrieve files later. | ||
/// | ||
/// `name` needs to be passed from the outside, since we only have | ||
/// access to it while we create the ObjectUrl. | ||
XFile( | ||
this.path, { | ||
this.mimeType, | ||
this.name, | ||
int length, | ||
Uint8List bytes, | ||
DateTime lastModified, | ||
@visibleForTesting CrossFileTestOverrides overrides, | ||
}) : _data = bytes, | ||
_length = length, | ||
_overrides = overrides, | ||
_lastModified = lastModified, | ||
super(path); | ||
|
||
/// Construct an CrossFile from its data | ||
XFile.fromData( | ||
Uint8List bytes, { | ||
this.mimeType, | ||
this.name, | ||
int length, | ||
DateTime lastModified, | ||
this.path, | ||
@visibleForTesting CrossFileTestOverrides overrides, | ||
}) : _data = bytes, | ||
_length = length, | ||
_overrides = overrides, | ||
_lastModified = lastModified, | ||
super(path) { | ||
if (path == null) { | ||
final blob = (mimeType == null) ? Blob([bytes]) : Blob([bytes], mimeType); | ||
this.path = Url.createObjectUrl(blob); | ||
} | ||
} | ||
|
||
@override | ||
Future<DateTime> lastModified() async { | ||
if (_lastModified != null) { | ||
return Future.value(_lastModified); | ||
} | ||
return null; | ||
} | ||
|
||
Future<Uint8List> get _bytes async { | ||
if (_data != null) { | ||
return Future.value(UnmodifiableUint8ListView(_data)); | ||
} | ||
return http.readBytes(path); | ||
} | ||
|
||
@override | ||
Future<int> length() async { | ||
return _length ?? (await _bytes).length; | ||
} | ||
|
||
@override | ||
Future<String> readAsString({Encoding encoding = utf8}) async { | ||
return encoding.decode(await _bytes); | ||
} | ||
|
||
@override | ||
Future<Uint8List> readAsBytes() async { | ||
return Future.value(await _bytes); | ||
} | ||
|
||
@override | ||
Stream<Uint8List> openRead([int start, int end]) async* { | ||
final bytes = await _bytes; | ||
yield bytes.sublist(start ?? 0, end ?? bytes.length); | ||
} | ||
|
||
/// Saves the data of this CrossFile at the location indicated by path. | ||
/// For the web implementation, the path variable is ignored. | ||
void saveTo(String path) async { | ||
// Create a DOM container where we can host the anchor. | ||
_target = ensureInitialized('__x_file_dom_element'); | ||
|
||
// Create an <a> tag with the appropriate download attributes and click it | ||
// May be overridden with CrossFileTestOverrides | ||
final AnchorElement element = | ||
(_hasTestOverrides && _overrides.createAnchorElement != null) | ||
? _overrides.createAnchorElement(this.path, this.name) | ||
: createAnchorElement(this.path, this.name); | ||
|
||
// Clear the children in our container so we can add an element to click | ||
_target.children.clear(); | ||
addElementToContainerAndClick(_target, element); | ||
} | ||
} | ||
|
||
/// Overrides some functions to allow testing | ||
@visibleForTesting | ||
class CrossFileTestOverrides { | ||
/// For overriding the creation of the file input element. | ||
Element Function(String href, String suggestedName) createAnchorElement; | ||
|
||
/// Default constructor for overrides | ||
CrossFileTestOverrides({this.createAnchorElement}); | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
// Copyright 2018 The Chromium Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
import 'dart:typed_data'; | ||
ditman marked this conversation as resolved.
Show resolved
Hide resolved
|
||
import 'package:meta/meta.dart'; | ||
|
||
import './base.dart'; | ||
|
||
/// A CrossFile is a cross-platform, simplified File abstraction. | ||
/// | ||
/// It wraps the bytes of a selected file, and its (platform-dependant) path. | ||
class XFile extends XFileBase { | ||
/// Construct a CrossFile object from its path. | ||
/// | ||
/// Optionally, this can be initialized with `bytes` and `length` | ||
/// so no http requests are performed to retrieve data later. | ||
/// | ||
/// `name` may be passed from the outside, for those cases where the effective | ||
/// `path` of the file doesn't match what the user sees when selecting it | ||
/// (like in web) | ||
XFile( | ||
String path, { | ||
String mimeType, | ||
String name, | ||
int length, | ||
Uint8List bytes, | ||
DateTime lastModified, | ||
@visibleForTesting CrossFileTestOverrides overrides, | ||
}) : super(path) { | ||
throw UnimplementedError( | ||
'CrossFile is not available in your current platform.'); | ||
} | ||
|
||
/// Construct a CrossFile object from its data | ||
XFile.fromData( | ||
Uint8List bytes, { | ||
String mimeType, | ||
String name, | ||
int length, | ||
DateTime lastModified, | ||
String path, | ||
@visibleForTesting CrossFileTestOverrides overrides, | ||
}) : super(path) { | ||
throw UnimplementedError( | ||
'CrossFile is not available in your current platform.'); | ||
} | ||
} | ||
|
||
/// Overrides some functions of CrossFile for testing purposes | ||
@visibleForTesting | ||
class CrossFileTestOverrides { | ||
/// For overriding the creation of the file input element. | ||
dynamic Function(String href, String suggestedName) createAnchorElement; | ||
|
||
/// Default constructor for overrides | ||
CrossFileTestOverrides({this.createAnchorElement}); | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.