Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.

Commit 576f04a

Browse files
[file_selector] Initial implementation (#3140)
Co-authored-by: Jason Panelli <[email protected]>
1 parent f15a800 commit 576f04a

22 files changed

+1038
-0
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
## 0.7.0
2+
3+
* Initial Open Source release.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
Copyright 2020 The Flutter Authors. All rights reserved.
2+
3+
Redistribution and use in source and binary forms, with or without modification,
4+
are permitted provided that the following conditions are met:
5+
6+
* Redistributions of source code must retain the above copyright
7+
notice, this list of conditions and the following disclaimer.
8+
* Redistributions in binary form must reproduce the above
9+
copyright notice, this list of conditions and the following
10+
disclaimer in the documentation and/or other materials provided
11+
with the distribution.
12+
* Neither the name of Google Inc. nor the names of its
13+
contributors may be used to endorse or promote products derived
14+
from this software without specific prior written permission.
15+
16+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
20+
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
23+
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# file_selector
2+
3+
[![pub package](https://img.shields.io/pub/v/file_selector.svg)](https://pub.dartlang.org/packages/file_selector)
4+
5+
A Flutter plugin that manages files and interactions with file dialogs.
6+
7+
## Usage
8+
To use this plugin, add `file_selector` as a [dependency in your pubspec.yaml file](https://flutter.dev/platform-plugins/).
9+
10+
### Examples
11+
Here are small examples that show you how to use the API.
12+
Please also take a look at our [example][example] app.
13+
14+
#### Open a single file
15+
``` dart
16+
final typeGroup = XTypeGroup(label: 'images', extensions: ['jpg', 'png']);
17+
final file = await openFile(acceptedTypeGroups: [typeGroup]);
18+
```
19+
20+
#### Open multiple files at once
21+
``` dart
22+
final typeGroup = XTypeGroup(label: 'images', extensions: ['jpg', 'png']);
23+
final files = await openFiles(acceptedTypeGroups: [typeGroup]);
24+
```
25+
26+
#### Saving a file
27+
```dart
28+
final path = await getSavePath();
29+
final name = "hello_file_selector.txt";
30+
final data = Uint8List.fromList("Hello World!".codeUnits);
31+
final mimeType = "text/plain";
32+
final file = XFile.fromData(data, name: name, mimeType: mimeType);
33+
await file.saveTo(path);
34+
```
35+
36+
[example]:./example
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# Miscellaneous
2+
*.class
3+
*.log
4+
*.pyc
5+
*.swp
6+
.DS_Store
7+
.atom/
8+
.buildlog/
9+
.history
10+
.svn/
11+
12+
# IntelliJ related
13+
*.iml
14+
*.ipr
15+
*.iws
16+
.idea/
17+
18+
# The .vscode folder contains launch configuration and tasks you configure in
19+
# VS Code which you may wish to be included in version control, so this line
20+
# is commented out by default.
21+
#.vscode/
22+
23+
# Flutter/Dart/Pub related
24+
**/doc/api/
25+
**/ios/Flutter/.last_build_id
26+
.dart_tool/
27+
.flutter-plugins
28+
.flutter-plugins-dependencies
29+
.packages
30+
.pub-cache/
31+
.pub/
32+
/build/
33+
34+
# Web related
35+
lib/generated_plugin_registrant.dart
36+
37+
# Symbolication related
38+
app.*.symbols
39+
40+
# Obfuscation related
41+
app.*.map.json
42+
43+
# Currently only web supported
44+
android/
45+
ios/
46+
47+
# Exceptions to above rules.
48+
!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# This file tracks properties of this Flutter project.
2+
# Used by Flutter tool to assess capabilities and perform upgrades etc.
3+
#
4+
# This file should be version controlled and should not be manually edited.
5+
6+
version:
7+
revision: 7736f3bc90270dcb0480db2ccffbf1d13c28db85
8+
channel: dev
9+
10+
project_type: app
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# file_selector_example
2+
3+
Demonstrates how to use the file_selector plugin.
4+
5+
## Getting Started
6+
7+
For help getting started with Flutter, view our online
8+
[documentation](https://flutter.dev/).
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import 'package:file_selector/file_selector.dart';
2+
import 'package:flutter/material.dart';
3+
4+
/// Screen that shows an example of getDirectoryPath
5+
class GetDirectoryPage extends StatelessWidget {
6+
void _getDirectoryPath(BuildContext context) async {
7+
final String confirmButtonText = 'Choose';
8+
final String directoryPath = await getDirectoryPath(
9+
confirmButtonText: confirmButtonText,
10+
);
11+
await showDialog(
12+
context: context,
13+
builder: (context) => TextDisplay(directoryPath),
14+
);
15+
}
16+
17+
@override
18+
Widget build(BuildContext context) {
19+
return Scaffold(
20+
appBar: AppBar(
21+
title: Text("Open a text file"),
22+
),
23+
body: Center(
24+
child: Column(
25+
mainAxisAlignment: MainAxisAlignment.center,
26+
children: <Widget>[
27+
RaisedButton(
28+
color: Colors.blue,
29+
textColor: Colors.white,
30+
child: Text('Press to ask user to choose a directory'),
31+
onPressed: () => _getDirectoryPath(context),
32+
),
33+
],
34+
),
35+
),
36+
);
37+
}
38+
}
39+
40+
/// Widget that displays a text file in a dialog
41+
class TextDisplay extends StatelessWidget {
42+
/// Directory path
43+
final String directoryPath;
44+
45+
/// Default Constructor
46+
TextDisplay(this.directoryPath);
47+
48+
@override
49+
Widget build(BuildContext context) {
50+
return AlertDialog(
51+
title: Text('Selected Directory'),
52+
content: Scrollbar(
53+
child: SingleChildScrollView(
54+
child: Text(directoryPath),
55+
),
56+
),
57+
actions: [
58+
FlatButton(
59+
child: const Text('Close'),
60+
onPressed: () => Navigator.pop(context),
61+
),
62+
],
63+
);
64+
}
65+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import 'package:flutter/material.dart';
2+
3+
/// Home Page of the application
4+
class HomePage extends StatelessWidget {
5+
@override
6+
Widget build(BuildContext context) {
7+
return Scaffold(
8+
appBar: AppBar(
9+
title: Text('File Selector Demo Home Page'),
10+
),
11+
body: Center(
12+
child: Column(
13+
mainAxisAlignment: MainAxisAlignment.center,
14+
children: <Widget>[
15+
RaisedButton(
16+
color: Colors.blue,
17+
textColor: Colors.white,
18+
child: Text('Open a text file'),
19+
onPressed: () => Navigator.pushNamed(context, '/open/text'),
20+
),
21+
SizedBox(height: 10),
22+
RaisedButton(
23+
color: Colors.blue,
24+
textColor: Colors.white,
25+
child: Text('Open an image'),
26+
onPressed: () => Navigator.pushNamed(context, '/open/image'),
27+
),
28+
SizedBox(height: 10),
29+
RaisedButton(
30+
color: Colors.blue,
31+
textColor: Colors.white,
32+
child: Text('Open multiple images'),
33+
onPressed: () => Navigator.pushNamed(context, '/open/images'),
34+
),
35+
SizedBox(height: 10),
36+
RaisedButton(
37+
color: Colors.blue,
38+
textColor: Colors.white,
39+
child: Text('Save a file'),
40+
onPressed: () => Navigator.pushNamed(context, '/save/text'),
41+
),
42+
SizedBox(height: 10),
43+
RaisedButton(
44+
color: Colors.blue,
45+
textColor: Colors.white,
46+
child: Text('Open a get directory dialog'),
47+
onPressed: () => Navigator.pushNamed(context, '/directory'),
48+
),
49+
],
50+
),
51+
),
52+
);
53+
}
54+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:example/home_page.dart';
3+
import 'package:example/get_directory_page.dart';
4+
import 'package:example/open_text_page.dart';
5+
import 'package:example/open_image_page.dart';
6+
import 'package:example/open_multiple_images_page.dart';
7+
import 'package:example/save_text_page.dart';
8+
9+
void main() {
10+
runApp(MyApp());
11+
}
12+
13+
/// MyApp is the Main Application
14+
class MyApp extends StatelessWidget {
15+
@override
16+
Widget build(BuildContext context) {
17+
return MaterialApp(
18+
title: 'File Selector Demo',
19+
theme: ThemeData(
20+
primarySwatch: Colors.blue,
21+
visualDensity: VisualDensity.adaptivePlatformDensity,
22+
),
23+
home: HomePage(),
24+
routes: {
25+
'/open/image': (context) => OpenImagePage(),
26+
'/open/images': (context) => OpenMultipleImagesPage(),
27+
'/open/text': (context) => OpenTextPage(),
28+
'/save/text': (context) => SaveTextPage(),
29+
'/directory': (context) => GetDirectoryPage(),
30+
},
31+
);
32+
}
33+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import 'dart:io';
2+
import 'package:flutter/foundation.dart';
3+
import 'package:file_selector/file_selector.dart';
4+
import 'package:flutter/material.dart';
5+
6+
/// Screen that shows an example of openFiles
7+
class OpenImagePage extends StatelessWidget {
8+
void _openImageFile(BuildContext context) async {
9+
final XTypeGroup typeGroup = XTypeGroup(
10+
label: 'images',
11+
extensions: ['jpg', 'png'],
12+
);
13+
final List<XFile> files = await openFiles(acceptedTypeGroups: [typeGroup]);
14+
final XFile file = files[0];
15+
final String fileName = file.name;
16+
final String filePath = file.path;
17+
18+
await showDialog(
19+
context: context,
20+
builder: (context) => ImageDisplay(fileName, filePath),
21+
);
22+
}
23+
24+
@override
25+
Widget build(BuildContext context) {
26+
return Scaffold(
27+
appBar: AppBar(
28+
title: Text("Open an image"),
29+
),
30+
body: Center(
31+
child: Column(
32+
mainAxisAlignment: MainAxisAlignment.center,
33+
children: <Widget>[
34+
RaisedButton(
35+
color: Colors.blue,
36+
textColor: Colors.white,
37+
child: Text('Press to open an image file(png, jpg)'),
38+
onPressed: () => _openImageFile(context),
39+
),
40+
],
41+
),
42+
),
43+
);
44+
}
45+
}
46+
47+
/// Widget that displays a text file in a dialog
48+
class ImageDisplay extends StatelessWidget {
49+
/// Image's name
50+
final String fileName;
51+
52+
/// Image's path
53+
final String filePath;
54+
55+
/// Default Constructor
56+
ImageDisplay(this.fileName, this.filePath);
57+
58+
@override
59+
Widget build(BuildContext context) {
60+
return AlertDialog(
61+
title: Text(fileName),
62+
// On web the filePath is a blob url
63+
// while on other platforms it is a system path.
64+
content: kIsWeb ? Image.network(filePath) : Image.file(File(filePath)),
65+
actions: [
66+
FlatButton(
67+
child: const Text('Close'),
68+
onPressed: () {
69+
Navigator.pop(context);
70+
},
71+
),
72+
],
73+
);
74+
}
75+
}

0 commit comments

Comments
 (0)