Skip to content

Commit 962ffa2

Browse files
authored
Merge pull request #5 from 4-alok/main
added formatBytes, readMe created, example ready, custom widget for empty folder
2 parents 8a27315 + f63f780 commit 962ffa2

File tree

4 files changed

+360
-79
lines changed

4 files changed

+360
-79
lines changed

README.md

Lines changed: 117 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,121 @@
1-
# file_manager
1+
# File Manager
22

3-
A new Flutter project.
3+
FileManager is a wonderful widget that allows you to manage files and folders, pick files and folders, and do a lot more.
4+
Designed to feel like part of the Flutter framework.
45

5-
## Getting Started
66

7-
This project is a starting point for a Dart
8-
[package](https://flutter.dev/developing-packages/),
9-
a library module containing code that can be shared easily across
10-
multiple Flutter or Dart projects.
7+
## Usage
118

12-
For help getting started with Flutter, view our
13-
[online documentation](https://flutter.dev/docs), which offers tutorials,
14-
samples, guidance on mobile development, and a full API reference.
9+
Make sure to check out [examples](https://github.com/DevsOnFlutter/file_manager/blob/main/example/lib/main.dart) for more details.
10+
11+
### Installation
12+
13+
Add the following line to `pubspec.yaml`:
14+
15+
```yaml
16+
dependencies:
17+
file_manager: ^1.0.0
18+
```
19+
20+
### Basic setup
21+
22+
*The complete example is available [here](https://github.com/4-alok/draggable_home/blob/main/example/lib/main.dart).*
23+
24+
Required parameter for **FileManager** are `controller` and `builder`
25+
* `controller` The controller updates value and notifies its listeners, and FileManager updates itself appropriately whenever the user modifies the path or changes the sort-type with an associated FileManagerController.
26+
```
27+
final FileManagerController controller = FileManagerController();
28+
```
29+
* `builder` This function allows you to create custom widgets and retrieve a list of entities `List<FileSystemEntity>.`
30+
31+
32+
33+
Sample code
34+
```dart
35+
FileManager(
36+
controller: controller,
37+
builder: (context, snapshot) {
38+
final List<FileSystemEntity> entitis = snapshot;
39+
return ListView.builder(
40+
itemCount: entitis.length,
41+
itemBuilder: (context, index) {
42+
return Card(
43+
child: ListTile(
44+
leading: isFile(entitis[index])
45+
? Icon(Icons.feed_outlined)
46+
: Icon(Icons.folder),
47+
title: Text(basename(entitis[index])),
48+
onTap: () {
49+
if (isDirectory(entitis[index])) {
50+
controller.openDirectory(entitis[index]); // open directory
51+
} else {
52+
// Perform file-related tasks.
53+
}
54+
},
55+
),
56+
);
57+
},
58+
);
59+
},
60+
),
61+
```
62+
63+
## FileManager
64+
| Properties | Description |
65+
|--------------|-----------------|
66+
| `loadingScreen` | For the loading screen, create a custom widget. A simple Centered CircularProgressIndicator is provided by default. |
67+
| `emptyFolder` | For an empty screen, create a custom widget. |
68+
| `controller` | For an empty screen, create a custom widget. |
69+
| `hideHiddenEntity` | Hide the files and folders that are hidden. |
70+
| `builder` | This function allows you to create custom widgets and retrieve a list of entities `List<FileSystemEntity>.` |
71+
72+
## FileManagerContoller
73+
| Properties | Description |
74+
|--------------|-----------------|
75+
| `getSortedBy` | The sorting type that is currently in use is returned. |
76+
| `setSortedBy` | is used to set the sorting type. `SortBy{ name, type, date, size }`. |
77+
| `getCurrentDirectory` | Get current Directory |
78+
| `getCurrentPath` | Get current path, similar to [getCurrentDirectory]. |
79+
| `setCurrentPath` | Set current directory path by providing `String` of path, similar to [openDirectory]. `List<FileSystemEntity>.` |
80+
| `goToParentDirectory` | `goToParentDirectory` returns `bool`, goes to the parent directory of currently opened directory if the parent is accessible, return true if current directory is the root. false, if the current directory not on root of the stogare.. |
81+
| `openDirectory` | Open directory by providing `Directory`. |
82+
83+
## Otheres
84+
| Properties | Description |
85+
|--------------|-----------------|
86+
| `isFile` | check weather FileSystemEntity is File. |
87+
| `isDirectory` | check weather FileSystemEntity is Directory. |
88+
| `basename` | Get the basename of Directory or File. Provide `File`, `Directory` or `FileSystemEntity` and returns the name as a `String`. ie
89+
```dart
90+
controller.dirName(dir);
91+
```
92+
|
93+
| `formatBytes` | Convert bytes to human readable size.[getCurrentDirectory]. |
94+
| `setCurrentPath` | Set current directory path by providing `String` of path, similar to [openDirectory]. `List<FileSystemEntity>.` |
95+
| `getStorageList` | Get list of available storage in the device, returns an empty list if there is no storage `List<Directory>`|
96+
97+
## Show some :heart: and :star: the repo
98+
99+
[![GitHub followers](https://img.shields.io/github/followers/4-alok?style=social)](https://github.com/4-alok/)
100+
[![GitHub followers](https://img.shields.io/github/stars/4-alok/draggable_home?style=social)](https://github.com/4-alok/)
101+
102+
## Contributions
103+
104+
Contributions are welcomed!
105+
106+
If you feel that a hook is missing, feel free to open a pull-request.
107+
108+
For a custom-hook to be merged, you will need to do the following:
109+
110+
- Describe the use-case.
111+
112+
- Open an issue explaining why we need this hook, how to use it, ...
113+
This is important as a hook will not get merged if the hook doens't appeal to
114+
a large number of people.
115+
116+
- If your hook is rejected, don't worry! A rejection doesn't mean that it won't
117+
be merged later in the future if more people shows an interest in it.
118+
In the mean-time, feel free to publish your hook as a package on https://pub.dev.
119+
120+
- A hook will not be merged unles fully tested, to avoid breaking it inadvertendly
121+
in the future.

example/lib/main.dart

Lines changed: 143 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import 'dart:io';
2+
13
import 'package:file_manager/file_manager.dart';
24
import 'package:flutter/material.dart';
35

@@ -26,13 +28,19 @@ class HomePage extends StatelessWidget {
2628

2729
@override
2830
Widget build(BuildContext context) {
31+
// Creates a widget that registers a callback to veto attempts by the user to dismiss the enclosing
32+
// or controllers the system's back button
2933
return WillPopScope(
3034
onWillPop: () async => (await controller.goToParentDirectory()),
3135
child: Scaffold(
3236
appBar: AppBar(
3337
actions: [
3438
IconButton(
35-
onPressed: () => controller.setCurrentStorage(storageIndex: 1),
39+
onPressed: () => sort(context),
40+
icon: Icon(Icons.sort_rounded),
41+
),
42+
IconButton(
43+
onPressed: () => selectStorage(context),
3644
icon: Icon(Icons.sd_storage_rounded),
3745
)
3846
],
@@ -48,18 +56,50 @@ class HomePage extends StatelessWidget {
4856
child: FileManager(
4957
controller: controller,
5058
builder: (context, snapshot) {
59+
final List<FileSystemEntity> entities = snapshot;
5160
return ListView.builder(
52-
itemCount: snapshot.length,
61+
itemCount: entities.length,
5362
itemBuilder: (context, index) {
63+
FileSystemEntity entity = entities[index];
5464
return Card(
5565
child: ListTile(
56-
leading: isFile(snapshot[index])
66+
leading: isFile(entity)
5767
? Icon(Icons.feed_outlined)
5868
: Icon(Icons.folder),
59-
title: Text(basename(snapshot[index])),
60-
onTap: () {
61-
if (isDirectory(snapshot[index]))
62-
controller.openDirectory(snapshot[index]);
69+
title: Text(basename(entity)),
70+
subtitle: subtitle(entity),
71+
onTap: () async {
72+
if (isDirectory(entity)) {
73+
// open the folder
74+
controller.openDirectory(entity);
75+
76+
// delete a folder
77+
// await entity.delete(recursive: true);
78+
79+
// rename a folder
80+
// await entity.rename("newPath");
81+
82+
// Check weather folder exists
83+
// entity.exists();
84+
85+
// get date of file
86+
// DateTime date = (await entity.stat()).modified;
87+
} else {
88+
// delete a file
89+
// await entity.delete();
90+
91+
// rename a file
92+
// await entity.rename("newPath");
93+
94+
// Check weather file exists
95+
// entity.exists();
96+
97+
// get date of file
98+
// DateTime date = (await entity.stat()).modified;
99+
100+
// get the size of the file
101+
// int size = (await entity.stat()).size;
102+
}
63103
},
64104
),
65105
);
@@ -70,4 +110,100 @@ class HomePage extends StatelessWidget {
70110
)),
71111
);
72112
}
113+
114+
Widget subtitle(FileSystemEntity entity) {
115+
return FutureBuilder<FileStat>(
116+
future: entity.stat(),
117+
builder: (context, snapshot) {
118+
if (snapshot.hasData) {
119+
if (entity is File) {
120+
int size = snapshot.data!.size;
121+
122+
return Text(
123+
"${formatBytes(size)}",
124+
);
125+
}
126+
return Text(
127+
"${snapshot.data!.modified}",
128+
);
129+
} else {
130+
return Text("");
131+
}
132+
},
133+
);
134+
}
135+
136+
selectStorage(BuildContext context) {
137+
showDialog(
138+
context: context,
139+
builder: (context) => Dialog(
140+
child: FutureBuilder<List<Directory>>(
141+
future: getStorageList(),
142+
builder: (context, snapshot) {
143+
if (snapshot.hasData) {
144+
final List<FileSystemEntity> storageList = snapshot.data!;
145+
return Padding(
146+
padding: const EdgeInsets.all(10.0),
147+
child: Column(
148+
mainAxisSize: MainAxisSize.min,
149+
children: storageList
150+
.map((e) => ListTile(
151+
title: Text(
152+
"${basename(e)}",
153+
),
154+
onTap: () {
155+
controller.openDirectory(e);
156+
Navigator.pop(context);
157+
},
158+
))
159+
.toList()),
160+
);
161+
}
162+
return Dialog(
163+
child: CircularProgressIndicator(),
164+
);
165+
},
166+
),
167+
),
168+
);
169+
}
170+
171+
sort(BuildContext context) async {
172+
showDialog(
173+
context: context,
174+
builder: (context) => Dialog(
175+
child: Container(
176+
padding: EdgeInsets.all(10),
177+
child: Column(
178+
mainAxisSize: MainAxisSize.min,
179+
children: [
180+
ListTile(
181+
title: Text("Name"),
182+
onTap: () {
183+
controller.sortedBy = SortBy.name;
184+
Navigator.pop(context);
185+
}),
186+
ListTile(
187+
title: Text("Size"),
188+
onTap: () {
189+
controller.sortedBy = SortBy.size;
190+
Navigator.pop(context);
191+
}),
192+
ListTile(
193+
title: Text("Date"),
194+
onTap: () {
195+
controller.sortedBy = SortBy.date;
196+
Navigator.pop(context);
197+
}),
198+
ListTile(
199+
title: Text("type"),
200+
onTap: () {
201+
controller.sortedBy = SortBy.type;
202+
Navigator.pop(context);
203+
}),
204+
],
205+
),
206+
),
207+
));
208+
}
73209
}

lib/controller/file_manager_controller.dart

Lines changed: 16 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4,62 +4,49 @@ import 'package:flutter/material.dart';
44

55
class FileManagerController extends ChangeNotifier {
66
String _path = "";
7-
int _currentStorage = 0;
87
SortBy _short = SortBy.size;
98

10-
// TODO: [Documentation]
11-
12-
/// getSorted by returns the current sorting type of the FileManager
9+
/// The sorting type that is currently in use is returned.
1310
SortBy get getSortedBy => _short;
14-
// TODO: [Documentation]
15-
/// setSortedBy is used to set the sorting type.
16-
set setSortedBy(SortBy sortType) {
11+
12+
/// [setSortedBy] is used to set the sorting type.
13+
///
14+
/// `SortBy{ name, type, date, size }`
15+
set sortedBy(SortBy sortType) {
1716
_short = sortType;
1817
notifyListeners();
1918
}
2019

21-
/// Get current directory path.
20+
/// Get current Directory.
2221
Directory get getCurrentDirectory => Directory(_path);
23-
String get getCurrentPath {
24-
return _path;
25-
}
2622

27-
/// Set current directory path by providing string of path.
23+
/// Get current path, similar to [getCurrentDirectory].
24+
String get getCurrentPath => _path;
25+
26+
/// Set current directory path by providing string of path, similar to [openDirectory].
2827
set setCurrentPath(String path) {
2928
_path = path;
3029
notifyListeners();
3130
}
3231

33-
// TODO: [Documentation]
34-
/// goToParentDirectory returns false and goes to the parent directory of currently opened directory if the parent is accessible,
35-
/// it will return true and pops the screen if the parent of currently opened directory is not accessible.
32+
/// [goToParentDirectory] returns [bool], goes to the parent directory of currently opened directory if the parent is accessible,
33+
/// return true if current directory is the root. false, if the current directory not on root of the stogare.
3634
Future<bool> goToParentDirectory() async {
37-
List<Directory> storageList = (await getStorageList())!;
35+
List<Directory> storageList = (await getStorageList());
3836
final bool willNotGoToParent = (storageList
3937
.where((element) => element.path == Directory(_path).path)
4038
.isNotEmpty);
4139
if (!willNotGoToParent) openDirectory(Directory(_path).parent);
4240
return willNotGoToParent;
4341
}
4442

45-
/// Open directory by providing Directory.
43+
/// Open directory by providing [Directory].
4644
void openDirectory(FileSystemEntity entity) {
4745
if (entity is Directory) {
4846
_path = entity.path;
4947
notifyListeners();
5048
} else {
51-
print(
52-
"FileSystemEntity entity is File. Please provide a Directory(folder) to be opened not File");
49+
throw ("FileSystemEntity entity is File. Please provide a Directory(folder) to be opened not File");
5350
}
5451
}
55-
56-
/// Get current storege. ie: 0 is for internal storage. 1, 2 and so on, if any external storage is available.
57-
int get getCurrentStorage => _currentStorage;
58-
59-
/// Set current storege. ie: 0 is for internal storage. 1, 2 and so on, if any external storage is available.
60-
Future<void> setCurrentStorage({required int storageIndex}) async {
61-
_currentStorage = storageIndex;
62-
_path = (await getStorageList())![storageIndex].path;
63-
notifyListeners();
64-
}
6552
}

0 commit comments

Comments
 (0)