Skip to content

Commit a5fde91

Browse files
committed
Using ValueNotifier
1 parent 49ee053 commit a5fde91

File tree

4 files changed

+117
-136
lines changed

4 files changed

+117
-136
lines changed

README.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,14 @@ Make sure to check out [examples](https://github.com/DevsOnFlutter/file_manager/
2424

2525
### Installation
2626

27-
Give storage permission to application
27+
**Dependencies** Add the following line to `pubspec.yaml`:
28+
29+
```yaml
30+
dependencies:
31+
file_manager: ^1.0.0
32+
```
33+
34+
### Give storage permission to application
2835
2936
**Android:** Beside needing to add **WRITE_EXTERNAL_STORAGE** and **READ_EXTERNAL_STORAGE** to your android/app/src/main/AndroidManifest.xml.
3037
@@ -48,13 +55,6 @@ also add for Android 10
4855
**You also need Runtime Request Permission**
4956
allow storage permission from app setting manually or you may use any package such as [`permission_handler`](https://pub.dev/packages/permission_handler).
5057

51-
Add the following line to `pubspec.yaml`:
52-
53-
```yaml
54-
dependencies:
55-
file_manager: ^1.0.0
56-
```
57-
5858
</hr>
5959

6060
### Basic setup

example/lib/main.dart

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,9 @@ class HomePage extends StatelessWidget {
5151
icon: Icon(Icons.sd_storage_rounded),
5252
)
5353
],
54-
title: StreamBuilder<String>(
55-
stream: controller.titleStream.stream,
56-
builder: (context, snapshot) {
57-
return Text(snapshot.data!);
58-
},
54+
title: ValueListenableBuilder<String>(
55+
valueListenable: controller.title,
56+
builder: (context, title, _) => Text(title),
5957
),
6058
leading: IconButton(
6159
icon: Icon(Icons.arrow_back),
@@ -76,13 +74,13 @@ class HomePage extends StatelessWidget {
7674
FileSystemEntity entity = entities[index];
7775
return Card(
7876
child: ListTile(
79-
leading: isFile(entity)
77+
leading: FileManager.isFile(entity)
8078
? Icon(Icons.feed_outlined)
8179
: Icon(Icons.folder),
82-
title: Text(basename(entity)),
80+
title: Text(FileManager.basename(entity)),
8381
subtitle: subtitle(entity),
8482
onTap: () async {
85-
if (isDirectory(entity)) {
83+
if (FileManager.isDirectory(entity)) {
8684
// open the folder
8785
controller.openDirectory(entity);
8886

@@ -133,7 +131,7 @@ class HomePage extends StatelessWidget {
133131
int size = snapshot.data!.size;
134132

135133
return Text(
136-
"${formatBytes(size)}",
134+
"${FileManager.formatBytes(size)}",
137135
);
138136
}
139137
return Text(
@@ -151,7 +149,7 @@ class HomePage extends StatelessWidget {
151149
context: context,
152150
builder: (context) => Dialog(
153151
child: FutureBuilder<List<Directory>>(
154-
future: getStorageList(),
152+
future: FileManager.getStorageList(),
155153
builder: (context, snapshot) {
156154
if (snapshot.hasData) {
157155
final List<FileSystemEntity> storageList = snapshot.data!;
@@ -162,7 +160,7 @@ class HomePage extends StatelessWidget {
162160
children: storageList
163161
.map((e) => ListTile(
164162
title: Text(
165-
"${basename(e)}",
163+
"${FileManager.basename(e)}",
166164
),
167165
onTap: () {
168166
controller.openDirectory(e);
Lines changed: 21 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,70 +1,65 @@
1-
import 'dart:async';
21
import 'dart:io';
32
import 'package:file_manager/file_manager.dart';
4-
import 'package:flutter/material.dart';
3+
import 'package:flutter/widgets.dart';
54

6-
class FileManagerController extends ChangeNotifier {
7-
StreamController<String> pathStream = StreamController<String>.broadcast();
8-
StreamController<String> titleStream = StreamController<String>.broadcast();
9-
String _path = "";
10-
SortBy _short = SortBy.size;
5+
class FileManagerController {
6+
final ValueNotifier<String> _path = ValueNotifier<String>('');
7+
final ValueNotifier<String> title = ValueNotifier<String>('');
8+
final ValueNotifier<SortBy> _short = ValueNotifier<SortBy>(SortBy.name);
119

1210
_updatePath(String path) {
13-
pathStream.add(path);
14-
_path = path;
15-
titleStream.add(path.split('/').last);
11+
_path.value = path;
12+
title.value = path.split('/').last;
1613
}
1714

15+
ValueNotifier<String> get getPathNotifier => _path;
16+
ValueNotifier<SortBy> get getSortedByNotifier => _short;
17+
1818
/// The sorting type that is currently in use is returned.
19-
SortBy get getSortedBy => _short;
19+
SortBy get getSortedBy => _short.value;
2020

2121
/// [setSortedBy] is used to set the sorting type.
2222
///
2323
/// `SortBy{ name, type, date, size }`
24-
set sortedBy(SortBy sortType) {
25-
_short = sortType;
26-
notifyListeners();
27-
}
24+
set sortedBy(SortBy sortType) => _short.value = sortType;
2825

2926
/// Get current Directory.
30-
Directory get getCurrentDirectory => Directory(_path);
27+
Directory get getCurrentDirectory => Directory(_path.value);
3128

3229
/// Get current path, similar to [getCurrentDirectory].
33-
String get getCurrentPath => _path;
30+
String get getCurrentPath => _path.value;
3431

3532
/// Set current directory path by providing string of path, similar to [openDirectory].
3633
set setCurrentPath(String path) {
3734
_updatePath(path);
38-
notifyListeners();
3935
}
4036

4137
/// return true if current directory is the root. false, if the current directory not on root of the stogare.
4238
Future<bool> isRootDirectory() async {
43-
final List<Directory> storageList = (await getStorageList());
39+
final List<Directory> storageList = (await FileManager.getStorageList());
4440
return (storageList
45-
.where((element) => element.path == Directory(_path).path)
41+
.where((element) => element.path == Directory(_path.value).path)
4642
.isNotEmpty);
4743
}
4844

4945
/// Jumps to the parent directory of currently opened directory if the parent is accessible.
5046
Future<void> goToParentDirectory() async {
51-
if (!(await isRootDirectory())) openDirectory(Directory(_path).parent);
47+
if (!(await isRootDirectory()))
48+
openDirectory(Directory(_path.value).parent);
5249
}
5350

5451
/// Open directory by providing [Directory].
5552
void openDirectory(FileSystemEntity entity) {
5653
if (entity is Directory) {
5754
_updatePath(entity.path);
58-
notifyListeners();
5955
} else {
6056
throw ("FileSystemEntity entity is File. Please provide a Directory(folder) to be opened not File");
6157
}
6258
}
6359

64-
@override
6560
void dispose() {
66-
super.dispose();
67-
pathStream.close();
68-
titleStream.close();
61+
_path.dispose();
62+
title.dispose();
63+
_short.dispose();
6964
}
7065
}

lib/file_manager.dart

Lines changed: 79 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -96,78 +96,6 @@ Future<List<FileSystemEntity>> _sortEntitysList(
9696
return [];
9797
}
9898

99-
/// check weather FileSystemEntity is File
100-
/// return true if FileSystemEntity is File else returns false
101-
bool isFile(FileSystemEntity entity) {
102-
return (entity is File);
103-
}
104-
105-
// check weather FileSystemEntity is Directory
106-
/// return true if FileSystemEntity is a Directory else returns Directory
107-
bool isDirectory(FileSystemEntity entity) {
108-
return (entity is Directory);
109-
}
110-
111-
/// Get the basename of Directory or File.
112-
///
113-
/// Provide [File], [Directory] or [FileSystemEntity] and returns the name as a [String].
114-
///
115-
/// ie:
116-
/// ```dart
117-
/// controller.basename(dir);
118-
/// ```
119-
/// to hide the extension of file, showFileExtension = flase
120-
String basename(dynamic entity, [bool showFileExtension = true]) {
121-
if (entity is Directory) {
122-
return entity.path.split('/').last;
123-
} else if (entity is File) {
124-
return (showFileExtension)
125-
? entity.path.split('/').last.split('.').first
126-
: entity.path.split('/').last;
127-
} else {
128-
print(
129-
"Please provide a Object of type File, Directory or FileSystemEntity");
130-
return "";
131-
}
132-
}
133-
134-
/// Convert bytes to human readable size
135-
String formatBytes(int bytes, [precision = 2]) {
136-
if (bytes != 0) {
137-
final double base = math.log(bytes) / math.log(1024);
138-
final suffix = const ['B', 'KB', 'MB', 'GB', 'TB'][base.floor()];
139-
final size = math.pow(1024, base - base.floor());
140-
return '${size.toStringAsFixed(2)} $suffix';
141-
} else {
142-
return "0B";
143-
}
144-
}
145-
146-
/// Get list of available storage in the device
147-
/// returns an empty list if there is no storage
148-
Future<List<Directory>> getStorageList() async {
149-
if (Platform.isAndroid) {
150-
List<Directory> storages = (await getExternalStorageDirectories())!;
151-
storages = storages.map((Directory e) {
152-
final List<String> splitedPath = e.path.split("/");
153-
return Directory(splitedPath
154-
.sublist(0, splitedPath.indexWhere((element) => element == "Android"))
155-
.join("/"));
156-
}).toList();
157-
return storages;
158-
} else if (Platform.isLinux) {
159-
final Directory dir = await getApplicationDocumentsDirectory();
160-
161-
// Gives the home directory.
162-
final Directory home = dir.parent;
163-
164-
// you may provide root directory.
165-
// final Directory root = dir.parent.parent.parent;
166-
return [home];
167-
}
168-
return [];
169-
}
170-
17199
/// FileManager is a wonderful widget that allows you to manage files and folders, pick files and folders, and do a lot more.
172100
/// Designed to feel like part of the Flutter framework.
173101
///
@@ -251,33 +179,92 @@ class FileManager extends StatefulWidget {
251179

252180
@override
253181
_FileManagerState createState() => _FileManagerState();
254-
}
255182

256-
class _FileManagerState extends State<FileManager> {
257-
final ValueNotifier<String> path = ValueNotifier<String>("");
258-
final ValueNotifier<SortBy> sort = ValueNotifier<SortBy>(SortBy.name);
183+
/// check weather FileSystemEntity is File
184+
/// return true if FileSystemEntity is File else returns false
185+
static bool isFile(FileSystemEntity entity) {
186+
return (entity is File);
187+
}
259188

260-
@override
261-
void initState() {
262-
super.initState();
189+
// check weather FileSystemEntity is Directory
190+
/// return true if FileSystemEntity is a Directory else returns Directory
191+
static bool isDirectory(FileSystemEntity entity) {
192+
return (entity is Directory);
193+
}
194+
195+
/// Get the basename of Directory or File.
196+
///
197+
/// Provide [File], [Directory] or [FileSystemEntity] and returns the name as a [String].
198+
///
199+
/// ie:
200+
/// ```dart
201+
/// controller.basename(dir);
202+
/// ```
203+
/// to hide the extension of file, showFileExtension = flase
204+
static String basename(dynamic entity, [bool showFileExtension = true]) {
205+
if (entity is Directory) {
206+
return entity.path.split('/').last;
207+
} else if (entity is File) {
208+
return (showFileExtension)
209+
? entity.path.split('/').last.split('.').first
210+
: entity.path.split('/').last;
211+
} else {
212+
print(
213+
"Please provide a Object of type File, Directory or FileSystemEntity");
214+
return "";
215+
}
216+
}
263217

264-
widget.controller.addListener(() {
265-
path.value = widget.controller.getCurrentPath;
266-
sort.value = widget.controller.getSortedBy;
267-
});
218+
/// Convert bytes to human readable size
219+
static String formatBytes(int bytes, [precision = 2]) {
220+
if (bytes != 0) {
221+
final double base = math.log(bytes) / math.log(1024);
222+
final suffix = const ['B', 'KB', 'MB', 'GB', 'TB'][base.floor()];
223+
final size = math.pow(1024, base - base.floor());
224+
return '${size.toStringAsFixed(2)} $suffix';
225+
} else {
226+
return "0B";
227+
}
268228
}
269229

230+
/// Get list of available storage in the device
231+
/// returns an empty list if there is no storage
232+
static Future<List<Directory>> getStorageList() async {
233+
if (Platform.isAndroid) {
234+
List<Directory> storages = (await getExternalStorageDirectories())!;
235+
storages = storages.map((Directory e) {
236+
final List<String> splitedPath = e.path.split("/");
237+
return Directory(splitedPath
238+
.sublist(
239+
0, splitedPath.indexWhere((element) => element == "Android"))
240+
.join("/"));
241+
}).toList();
242+
return storages;
243+
} else if (Platform.isLinux) {
244+
final Directory dir = await getApplicationDocumentsDirectory();
245+
246+
// Gives the home directory.
247+
final Directory home = dir.parent;
248+
249+
// you may provide root directory.
250+
// final Directory root = dir.parent.parent.parent;
251+
return [home];
252+
}
253+
return [];
254+
}
255+
}
256+
257+
class _FileManagerState extends State<FileManager> {
270258
@override
271259
void dispose() {
272-
path.dispose();
273-
sort.dispose();
260+
widget.controller.dispose();
274261
super.dispose();
275262
}
276263

277264
@override
278265
Widget build(BuildContext context) {
279266
return FutureBuilder<List<Directory>?>(
280-
future: getStorageList(),
267+
future: FileManager.getStorageList(),
281268
builder: (context, snapshot) {
282269
if (snapshot.hasData) {
283270
widget.controller.setCurrentPath = snapshot.data!.first.path;
@@ -294,13 +281,14 @@ class _FileManagerState extends State<FileManager> {
294281

295282
Widget _body(BuildContext context) {
296283
return ValueListenableBuilder<String>(
297-
valueListenable: path,
284+
valueListenable: widget.controller.getPathNotifier,
298285
builder: (context, pathSnapshot, _) {
299286
return ValueListenableBuilder<SortBy>(
300-
valueListenable: sort,
287+
valueListenable: widget.controller.getSortedByNotifier,
301288
builder: (context, snapshot, _) {
302289
return FutureBuilder<List<FileSystemEntity>>(
303-
future: _sortEntitysList(pathSnapshot, sort.value),
290+
future: _sortEntitysList(pathSnapshot,
291+
widget.controller.getSortedByNotifier.value),
304292
builder: (context, snapshot) {
305293
if (snapshot.hasData) {
306294
List<FileSystemEntity> entitys = snapshot.data!;
@@ -309,8 +297,8 @@ class _FileManagerState extends State<FileManager> {
309297
}
310298
if (widget.hideHiddenEntity) {
311299
entitys = entitys.where((element) {
312-
if (basename(element) == "" ||
313-
basename(element).startsWith('.')) {
300+
if (FileManager.basename(element) == "" ||
301+
FileManager.basename(element).startsWith('.')) {
314302
return false;
315303
} else {
316304
return true;

0 commit comments

Comments
 (0)