Skip to content

added formatBytes, readMe created, example ready, custom widget for empty folder #5

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jun 30, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
127 changes: 117 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,121 @@
# file_manager
# File Manager

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

## Getting Started

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

For help getting started with Flutter, view our
[online documentation](https://flutter.dev/docs), which offers tutorials,
samples, guidance on mobile development, and a full API reference.
Make sure to check out [examples](https://github.com/DevsOnFlutter/file_manager/blob/main/example/lib/main.dart) for more details.

### Installation

Add the following line to `pubspec.yaml`:

```yaml
dependencies:
file_manager: ^1.0.0
```

### Basic setup

*The complete example is available [here](https://github.com/4-alok/draggable_home/blob/main/example/lib/main.dart).*

Required parameter for **FileManager** are `controller` and `builder`
* `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.
```
final FileManagerController controller = FileManagerController();
```
* `builder` This function allows you to create custom widgets and retrieve a list of entities `List<FileSystemEntity>.`



Sample code
```dart
FileManager(
controller: controller,
builder: (context, snapshot) {
final List<FileSystemEntity> entitis = snapshot;
return ListView.builder(
itemCount: entitis.length,
itemBuilder: (context, index) {
return Card(
child: ListTile(
leading: isFile(entitis[index])
? Icon(Icons.feed_outlined)
: Icon(Icons.folder),
title: Text(basename(entitis[index])),
onTap: () {
if (isDirectory(entitis[index])) {
controller.openDirectory(entitis[index]); // open directory
} else {
// Perform file-related tasks.
}
},
),
);
},
);
},
),
```

## FileManager
| Properties | Description |
|--------------|-----------------|
| `loadingScreen` | For the loading screen, create a custom widget. A simple Centered CircularProgressIndicator is provided by default. |
| `emptyFolder` | For an empty screen, create a custom widget. |
| `controller` | For an empty screen, create a custom widget. |
| `hideHiddenEntity` | Hide the files and folders that are hidden. |
| `builder` | This function allows you to create custom widgets and retrieve a list of entities `List<FileSystemEntity>.` |

## FileManagerContoller
| Properties | Description |
|--------------|-----------------|
| `getSortedBy` | The sorting type that is currently in use is returned. |
| `setSortedBy` | is used to set the sorting type. `SortBy{ name, type, date, size }`. |
| `getCurrentDirectory` | Get current Directory |
| `getCurrentPath` | Get current path, similar to [getCurrentDirectory]. |
| `setCurrentPath` | Set current directory path by providing `String` of path, similar to [openDirectory]. `List<FileSystemEntity>.` |
| `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.. |
| `openDirectory` | Open directory by providing `Directory`. |

## Otheres
| Properties | Description |
|--------------|-----------------|
| `isFile` | check weather FileSystemEntity is File. |
| `isDirectory` | check weather FileSystemEntity is Directory. |
| `basename` | Get the basename of Directory or File. Provide `File`, `Directory` or `FileSystemEntity` and returns the name as a `String`. ie
```dart
controller.dirName(dir);
```
|
| `formatBytes` | Convert bytes to human readable size.[getCurrentDirectory]. |
| `setCurrentPath` | Set current directory path by providing `String` of path, similar to [openDirectory]. `List<FileSystemEntity>.` |
| `getStorageList` | Get list of available storage in the device, returns an empty list if there is no storage `List<Directory>`|

## Show some :heart: and :star: the repo

[![GitHub followers](https://img.shields.io/github/followers/4-alok?style=social)](https://github.com/4-alok/)
[![GitHub followers](https://img.shields.io/github/stars/4-alok/draggable_home?style=social)](https://github.com/4-alok/)

## Contributions

Contributions are welcomed!

If you feel that a hook is missing, feel free to open a pull-request.

For a custom-hook to be merged, you will need to do the following:

- Describe the use-case.

- Open an issue explaining why we need this hook, how to use it, ...
This is important as a hook will not get merged if the hook doens't appeal to
a large number of people.

- If your hook is rejected, don't worry! A rejection doesn't mean that it won't
be merged later in the future if more people shows an interest in it.
In the mean-time, feel free to publish your hook as a package on https://pub.dev.

- A hook will not be merged unles fully tested, to avoid breaking it inadvertendly
in the future.
150 changes: 143 additions & 7 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import 'dart:io';

import 'package:file_manager/file_manager.dart';
import 'package:flutter/material.dart';

Expand Down Expand Up @@ -26,13 +28,19 @@ class HomePage extends StatelessWidget {

@override
Widget build(BuildContext context) {
// Creates a widget that registers a callback to veto attempts by the user to dismiss the enclosing
// or controllers the system's back button
return WillPopScope(
onWillPop: () async => (await controller.goToParentDirectory()),
child: Scaffold(
appBar: AppBar(
actions: [
IconButton(
onPressed: () => controller.setCurrentStorage(storageIndex: 1),
onPressed: () => sort(context),
icon: Icon(Icons.sort_rounded),
),
IconButton(
onPressed: () => selectStorage(context),
icon: Icon(Icons.sd_storage_rounded),
)
],
Expand All @@ -48,18 +56,50 @@ class HomePage extends StatelessWidget {
child: FileManager(
controller: controller,
builder: (context, snapshot) {
final List<FileSystemEntity> entities = snapshot;
return ListView.builder(
itemCount: snapshot.length,
itemCount: entities.length,
itemBuilder: (context, index) {
FileSystemEntity entity = entities[index];
return Card(
child: ListTile(
leading: isFile(snapshot[index])
leading: isFile(entity)
? Icon(Icons.feed_outlined)
: Icon(Icons.folder),
title: Text(basename(snapshot[index])),
onTap: () {
if (isDirectory(snapshot[index]))
controller.openDirectory(snapshot[index]);
title: Text(basename(entity)),
subtitle: subtitle(entity),
onTap: () async {
if (isDirectory(entity)) {
// open the folder
controller.openDirectory(entity);

// delete a folder
// await entity.delete(recursive: true);

// rename a folder
// await entity.rename("newPath");

// Check weather folder exists
// entity.exists();

// get date of file
// DateTime date = (await entity.stat()).modified;
} else {
// delete a file
// await entity.delete();

// rename a file
// await entity.rename("newPath");

// Check weather file exists
// entity.exists();

// get date of file
// DateTime date = (await entity.stat()).modified;

// get the size of the file
// int size = (await entity.stat()).size;
}
},
),
);
Expand All @@ -70,4 +110,100 @@ class HomePage extends StatelessWidget {
)),
);
}

Widget subtitle(FileSystemEntity entity) {
return FutureBuilder<FileStat>(
future: entity.stat(),
builder: (context, snapshot) {
if (snapshot.hasData) {
if (entity is File) {
int size = snapshot.data!.size;

return Text(
"${formatBytes(size)}",
);
}
return Text(
"${snapshot.data!.modified}",
);
} else {
return Text("");
}
},
);
}

selectStorage(BuildContext context) {
showDialog(
context: context,
builder: (context) => Dialog(
child: FutureBuilder<List<Directory>>(
future: getStorageList(),
builder: (context, snapshot) {
if (snapshot.hasData) {
final List<FileSystemEntity> storageList = snapshot.data!;
return Padding(
padding: const EdgeInsets.all(10.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: storageList
.map((e) => ListTile(
title: Text(
"${basename(e)}",
),
onTap: () {
controller.openDirectory(e);
Navigator.pop(context);
},
))
.toList()),
);
}
return Dialog(
child: CircularProgressIndicator(),
);
},
),
),
);
}

sort(BuildContext context) async {
showDialog(
context: context,
builder: (context) => Dialog(
child: Container(
padding: EdgeInsets.all(10),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
ListTile(
title: Text("Name"),
onTap: () {
controller.sortedBy = SortBy.name;
Navigator.pop(context);
}),
ListTile(
title: Text("Size"),
onTap: () {
controller.sortedBy = SortBy.size;
Navigator.pop(context);
}),
ListTile(
title: Text("Date"),
onTap: () {
controller.sortedBy = SortBy.date;
Navigator.pop(context);
}),
ListTile(
title: Text("type"),
onTap: () {
controller.sortedBy = SortBy.type;
Navigator.pop(context);
}),
],
),
),
));
}
}
45 changes: 16 additions & 29 deletions lib/controller/file_manager_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,62 +4,49 @@ import 'package:flutter/material.dart';

class FileManagerController extends ChangeNotifier {
String _path = "";
int _currentStorage = 0;
SortBy _short = SortBy.size;

// TODO: [Documentation]

/// getSorted by returns the current sorting type of the FileManager
/// The sorting type that is currently in use is returned.
SortBy get getSortedBy => _short;
// TODO: [Documentation]
/// setSortedBy is used to set the sorting type.
set setSortedBy(SortBy sortType) {

/// [setSortedBy] is used to set the sorting type.
///
/// `SortBy{ name, type, date, size }`
set sortedBy(SortBy sortType) {
_short = sortType;
notifyListeners();
}

/// Get current directory path.
/// Get current Directory.
Directory get getCurrentDirectory => Directory(_path);
String get getCurrentPath {
return _path;
}

/// Set current directory path by providing string of path.
/// Get current path, similar to [getCurrentDirectory].
String get getCurrentPath => _path;

/// Set current directory path by providing string of path, similar to [openDirectory].
set setCurrentPath(String path) {
_path = path;
notifyListeners();
}

// TODO: [Documentation]
/// goToParentDirectory returns false and goes to the parent directory of currently opened directory if the parent is accessible,
/// it will return true and pops the screen if the parent of currently opened directory is not accessible.
/// [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.
Future<bool> goToParentDirectory() async {
List<Directory> storageList = (await getStorageList())!;
List<Directory> storageList = (await getStorageList());
final bool willNotGoToParent = (storageList
.where((element) => element.path == Directory(_path).path)
.isNotEmpty);
if (!willNotGoToParent) openDirectory(Directory(_path).parent);
return willNotGoToParent;
}

/// Open directory by providing Directory.
/// Open directory by providing [Directory].
void openDirectory(FileSystemEntity entity) {
if (entity is Directory) {
_path = entity.path;
notifyListeners();
} else {
print(
"FileSystemEntity entity is File. Please provide a Directory(folder) to be opened not File");
throw ("FileSystemEntity entity is File. Please provide a Directory(folder) to be opened not File");
}
}

/// Get current storege. ie: 0 is for internal storage. 1, 2 and so on, if any external storage is available.
int get getCurrentStorage => _currentStorage;

/// Set current storege. ie: 0 is for internal storage. 1, 2 and so on, if any external storage is available.
Future<void> setCurrentStorage({required int storageIndex}) async {
_currentStorage = storageIndex;
_path = (await getStorageList())![storageIndex].path;
notifyListeners();
}
}
Loading