Skip to content

Commit b2f97d8

Browse files
authored
Features, Fixes, Chore. (#12)
- Feature: instantiation `DocumentThumbnail` `fromUri()` static method. - Feature: instantiation `DocumentFile` `fromUri()` static method. - Fixes: for `share()` `open()` - title is optional parameter - Chore: updated README.md, CHANGELOG.md, documentation, example, dependencies, gradle, kotlin, java. Signed-off-by: Alex Yackers <7115964+yackers@users.noreply.github.com>
1 parent 43c898e commit b2f97d8

12 files changed

Lines changed: 207 additions & 40 deletions

File tree

CHANGELOG.md

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,69 @@
1+
## 1.2.0
2+
3+
* New Feature: Added method `all()` for `DocMan.dir` helper.
4+
It's a simple way to get all app directories in one call as map.
5+
6+
```dart
7+
/// Get all app directories as map with keys as directory names and values as paths.
8+
final Map<String, String> dirs = await DocMan.dir.all();
9+
10+
///Result example:
11+
{
12+
"cache": "/data/user/0/com.example.app/cache",
13+
"files": "/data/user/0/com.example.app/files",
14+
"data": "/data/user/0/com.example.app/app_flutter",
15+
// External directories, can be empty strings if not available.
16+
"cacheExt": "/storage/emulated/0/Android/data/com.example.app/cache",
17+
"filesExt": "/storage/emulated/0/Android/data/com.example.app/files",
18+
}
19+
```
20+
* Feature: Added ability to instantiate `DocumentThumbnail` from `Content Uri` or `File.path`.
21+
Same as `DocumentFile.thumbnail()` method, but now you can get `DocumentThumbnail` directly.
22+
23+
```dart
24+
/// Create thumbnail from content uri or file path.
25+
final DocumentThumbnail thumbnail = await DocumentThumbnail.fromUri(
26+
contentUriOrFilePath,
27+
width: 100,
28+
height: 100,
29+
png: true,
30+
);
31+
```
32+
* Feature: Added syntax sugar for `DocumentFile` instantiation from `Content Uri` or `File.path`.
33+
34+
```dart
35+
/// New syntax sugar for DocumentFile instantiation from content uri or file path.
36+
final DocumentFile? doc = await DocumentFile.fromUri(contentUriOrFilePath);
37+
38+
/// Old way.
39+
final DocumentFile? doc = await DocumentFile(contentUriOrFilePath).get();
40+
```
41+
* Fix: problem with parallel calls to `DocumentFile` `action` methods, when working with different
42+
documents.
43+
Now it's fixed. `DocManQueueManager` was primarily used for all `activity` methods, and it caused the problem.
44+
For example, now it's possible to create list or grid of documents thumbnails without any problems.
45+
If you were getting errors in log like `Error loading thumbnail: AlreadyRunning Method: documentfileaction`, it should
46+
be fixed now.
47+
48+
* Fix: error in syntax in methods `DocumentFile.share()` & `DocumentFile.open()`.
49+
String `title` parameter was not optional, but it should be. Now it's fixed.
50+
51+
Please check your code and change `title` parameter to optional if you are using these methods.
52+
53+
**From:**
54+
```dart
55+
final bool share = await doc.share('Share this document:');
56+
final bool open = await doc.open('Open with:');
57+
```
58+
59+
**To:**
60+
```dart
61+
final bool share = await doc.share(title: 'Share this document:');
62+
final bool open = await doc.open(title: 'Open with:');
63+
```
64+
65+
* Chore: Updated dependencies, updated example, updated README, some code cleanup & small fixes.
66+
167
## 1.1.0
268
369
* New Feature: Implemented simple custom `DocumentsProvider`

README.md

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
[![License: MIT](https://img.shields.io/github/license/devdfcom/docman?style=flat&color=mediumseagreen)](https://opensource.org/licenses/MIT)
99
[![Request a feature](https://img.shields.io/badge/Request-Feature-teal?style=flat)](https://github.com/devdfcom/docman/discussions/new?category=ideas)
1010
[![Ask a question](https://img.shields.io/badge/Ask-Question-royalblue?style=flat)](https://github.com/devdfcom/docman/discussions/new/choose)
11-
[![Report a bug](https://img.shields.io/badge/Report-Bug-indianred?style=flat)](https://github.com/devdfcom/docman/issues/new?labels=bug&projects=&template=bug_report.yml&title=%3Ctitle%3E)
11+
[![Report a bug](https://img.shields.io/badge/Report-Bug-indianred?style=flat)](https://github.com/devdfcom/docman/issues/new?labels=bug&projects=&template=bug_report.yml)
1212

1313
A Flutter plugin that simplifies file & directory operations on Android devices.
1414
Leveraging the Storage Access Framework (SAF) API,
@@ -277,7 +277,7 @@ Only `cacheExt` & `filesExt` can be empty strings if external storage is not ava
277277
///Get all directories at once via helper method
278278
Future<void> getAllDirs() async {
279279
final Map<String, String> dirs = await DocMan.dir.all();
280-
280+
281281
print(dirs);
282282
}
283283
@@ -504,6 +504,9 @@ There are two ways to instantiate a `DocumentFile`:
504504
```dart
505505
Future<DocumentFile?> backupDir() =>
506506
DocumentFile(uri: 'content://com.android.externalstorage.documents/tree/primary%3ADocMan').get();
507+
///Or you can use static method fromUri
508+
Future<DocumentFile?> backupDir() =>
509+
DocumentFile.fromUri('content://com.android.externalstorage.documents/tree/primary%3ADocMan');
507510
```
508511

509512
> [!CAUTION]
@@ -516,9 +519,13 @@ There are two ways to instantiate a `DocumentFile`:
516519

517520
```dart
518521
Future<DocumentFile?> file() => DocumentFile(uri: 'path/to/file.jpg').get();
522+
///Or you can use static method fromUri
523+
Future<DocumentFile?> file() => DocumentFile.fromUri('path/to/file.jpg');
519524
520525
/// If directory doesn't exist, it will create all directories in the path.
521526
Future<DocumentFile?> dir() => DocumentFile(uri: 'path/to/some/directory/notCreatedYet').get();
527+
///Or you can use static method fromUri
528+
Future<DocumentFile?> dir() => DocumentFile.fromUri('path/to/some/directory/notCreatedYet');
522529
```
523530

524531
#### **DocumentFile Activity methods**
@@ -532,15 +539,19 @@ Like `open`, `share`, `saveTo` methods. All methods are called through Activity
532539
the system will show a dialog to choose the app to open with.
533540
Action can be performed only on file & file must exist.
534541

535-
```dart
536-
Future<bool> openFile(DocumentFile file) => file.open('Open with:');
537-
```
542+
* `title` parameter is optional, and not working on all devices, depends on the system.
543+
544+
```dart
545+
Future<bool> openFile(DocumentFile file) => file.open(title: 'Open with:'); //or file.open();
546+
```
538547
539548
- `share` `📄` Share the file with other apps.
540549
541-
```dart
542-
Future<bool> shareFile(DocumentFile file) => file.share('Share with:');
543-
```
550+
* `title` parameter is optional, and not working on all devices, depends on the system.
551+
552+
```dart
553+
Future<bool> shareFile(DocumentFile file) => file.share(title: 'Share with:'); //or file.share();
554+
```
544555
545556
- `saveTo` `📄` Save the file to the selected directory.
546557
@@ -736,6 +747,8 @@ and can be performed in the background (with isolates or WorkManager).
736747
file.moveTo('/data/user/0/devdf.plugins.docman_example/cache/TempDir', name: 'moved_file.txt');
737748
```
738749
750+
<a name="documentfile-action-thumbnail"></a>
751+
739752
- `thumbnail` `📄` Get the thumbnail of the file.
740753
741754
Can be used only on file & file must exist & has flag `canThumbnail` set to `true`.
@@ -768,9 +781,24 @@ and can be performed in the background (with isolates or WorkManager).
768781
769782
#### 🧩 **DocumentThumbnail class**
770783
771-
`DocumentThumbnail` is a data class that holds information about the thumbnail image.
784+
`DocumentThumbnail` is a class that holds information about the thumbnail image.
772785
It stores the `width`, `height` of the image, and the `bytes` (Uint8List) of the image.
773786
787+
`📄` You can instantiate the `DocumentThumbnail` via static method `fromUri()` or from `DocumentFile` instance via
788+
[`DocumentFile.thumbnail()`](#documentfile-action-thumbnail) method.
789+
790+
You must specify the width & height of the thumbnail. Optionally you can specify the quality of the image
791+
and set `png` or `webp` to `true` to get the compressed image in that format, otherwise it will be `jpeg`.
792+
Returns [DocumentThumbnail](#-documentthumbnail-class) instance of the thumbnail image or `null` if the thumbnail is
793+
not available. Commonly used for images, videos, pdfs.
794+
795+
```dart
796+
/// It can be instantiated from `Content Uri` or `File.path` via static method.
797+
Future<DocumentThumbnail?> getThumbnail(String contentUriOrFilePath) async {
798+
return await DocumentThumbnail.fromUri(contentUriOrFilePath, width: 192, height: 192, png: true, quality: 100);
799+
}
800+
```
801+
774802
#### **Unsupported methods**
775803

776804
Information about currently (temporarily) unsupported methods in the plugin.

android/build.gradle

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@ group = "devdf.plugins.docman"
22
version = "1.0-SNAPSHOT"
33

44
buildscript {
5-
ext.kotlin_version = "1.8.22"
5+
ext.kotlin_version = "2.0.20"
66
repositories {
77
google()
88
mavenCentral()
99
}
1010

1111
dependencies {
12-
classpath("com.android.tools.build:gradle:8.5.2")
12+
classpath("com.android.tools.build:gradle:8.8.0")
1313
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version")
1414
}
1515
}
@@ -29,15 +29,15 @@ android {
2929
namespace = "devdf.plugins.docman"
3030
}
3131

32-
compileSdk = 34
32+
compileSdk = 35
3333

3434
compileOptions {
35-
sourceCompatibility = JavaVersion.VERSION_1_8
36-
targetCompatibility = JavaVersion.VERSION_1_8
35+
sourceCompatibility = JavaVersion.VERSION_17
36+
targetCompatibility = JavaVersion.VERSION_17
3737
}
3838

3939
kotlinOptions {
40-
jvmTarget = JavaVersion.VERSION_1_8
40+
jvmTarget = JavaVersion.VERSION_17
4141
}
4242

4343
sourceSets {
@@ -69,5 +69,5 @@ android {
6969

7070
dependencies {
7171
implementation 'androidx.documentfile:documentfile:1.0.1'
72-
implementation 'androidx.activity:activity-ktx:1.9.3'
72+
implementation 'androidx.activity:activity-ktx:1.10.0'
7373
}

example/android/app/build.gradle

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,12 @@ android {
1111
ndkVersion = flutter.ndkVersion
1212

1313
compileOptions {
14-
sourceCompatibility = JavaVersion.VERSION_1_8
15-
targetCompatibility = JavaVersion.VERSION_1_8
14+
sourceCompatibility = JavaVersion.VERSION_17
15+
targetCompatibility = JavaVersion.VERSION_17
1616
}
1717

1818
kotlinOptions {
19-
jvmTarget = JavaVersion.VERSION_1_8
19+
jvmTarget = JavaVersion.VERSION_17
2020
}
2121

2222
defaultConfig {

example/android/gradle/wrapper/gradle-wrapper.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
22
distributionPath=wrapper/dists
33
zipStoreBase=GRADLE_USER_HOME
44
zipStorePath=wrapper/dists
5-
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-all.zip
5+
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip

example/android/settings.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ pluginManagement {
1818

1919
plugins {
2020
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
21-
id "com.android.application" version "8.1.4" apply false
22-
id "org.jetbrains.kotlin.android" version "1.8.22" apply false
21+
id "com.android.application" version "8.8.0" apply false
22+
id "org.jetbrains.kotlin.android" version "2.0.20" apply false
2323
}
2424

2525
include ":app"

example/lib/src/ui/pages/documentfile/actions_document_file.dart

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,10 @@ class _ActionsDocumentFileState extends State<ActionsDocumentFile> {
120120
? exception.title
121121
: 'Permissions for: ${_document?.name}',
122122
subTitle: exception?.subTitle,
123-
result: exception?.result ?? perms.toString(),
123+
result: exception?.result ??
124+
(perms == null
125+
? 'DocumentFile has no persisted permissions'
126+
: perms.toString()),
124127
isResultOk: exception == null && perms != null,
125128
),
126129
]);
@@ -431,24 +434,44 @@ class _ActionsDocumentFileState extends State<ActionsDocumentFile> {
431434
)
432435
]);
433436
} else {
437+
//2.1. Set thumbnail method
438+
//There are currently 2 ways to get thumbnail
439+
// First to get thumbnail via `document.thumbnail()` method or by instantiating `DocumentThumbnail` class
440+
// Both methods are same, depending on what you prefer
441+
// Here commented out example of `document.thumbnail()` method, old one, just to show the difference
442+
443+
/// final thumbnailMethod = _document!.thumbnail(
444+
/// width: _thumbWidth,
445+
/// height: _thumbHeight,
446+
/// quality: _thumbQuality,
447+
/// png: png,
448+
/// webp: webp,
449+
/// );
450+
451+
//2.2. Get thumbnail via `DocumentThumbnail.fromUri()` method
452+
final thumbnailMethod = DocumentThumbnail.fromUri(
453+
_document!.uri,
454+
width: _thumbWidth,
455+
height: _thumbHeight,
456+
quality: _thumbQuality,
457+
png: png,
458+
webp: webp,
459+
);
460+
434461
//3. Set thumbnail widget to result
435462
widget.onResultWidgets([
436463
MethodApiWidget(
437464
MethodApiEntry(
465+
//name: 'DocumentFile.thumbnail(width: $_thumbWidth, height: $_thumbHeight, quality: $_thumbQuality, png: $png, webp: $webp)',
438466
name:
439-
'DocumentFile.thumbnail(width: $_thumbWidth, height: $_thumbHeight, quality: $_thumbQuality, png: $png, webp: $webp)',
467+
'DocumentThumbnail.fromUri(${_document!.uri}, width: $_thumbWidth, height: $_thumbHeight, quality: $_thumbQuality, png: $png, webp: $webp)',
440468
subTitle: 'Future intentionally delayed for 2 seconds'),
441469
endDivider: false,
442470
),
443471
ThumbResultWidget(
444472
maxWidth: _thumbWidth,
445473
maxHeight: _thumbHeight,
446-
getThumb: _document!.thumbnail(
447-
width: _thumbWidth,
448-
height: _thumbHeight,
449-
quality: _thumbQuality,
450-
png: png,
451-
webp: webp),
474+
getThumb: thumbnailMethod,
452475
)
453476
]);
454477
}

example/lib/src/ui/pages/documentfile/activity_document_file.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ class _ActivityDocumentFileState extends State<ActivityDocumentFile> {
4646
MethodApiEntry? exception;
4747

4848
try {
49-
isOpened = await widget.document!.open('Open Document with');
49+
isOpened = await widget.document!.open(title: 'Open Document with');
5050
} catch (e) {
5151
exception = _exceptionEntry(e);
5252
}
@@ -71,7 +71,7 @@ class _ActivityDocumentFileState extends State<ActivityDocumentFile> {
7171
MethodApiEntry? exception;
7272

7373
try {
74-
isShared = await widget.document!.share('Share Document with');
74+
isShared = await widget.document!.share(title: 'Share Document with');
7575
} catch (e) {
7676
exception = _exceptionEntry(e);
7777
}

example/lib/src/ui/pages/documentfile/init_document_file.dart

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,12 @@ class _InitDocumentFileState extends State<InitDocumentFile> {
172172
final filePath = await _getFilePath();
173173
//2. Create DocumentFile from file path
174174
try {
175-
doc = await DocumentFile(uri: filePath).get();
175+
//2.1 In DocMan v1.2.0 was added static method `fromUri` for `DocumentFile`
176+
//So from now on it's possible to instantiate DocumentFile via `DocumentFile.fromUri(uri)`
177+
doc = await DocumentFile.fromUri(filePath);
178+
179+
///Before v1.2.0 it was possible to instantiate DocumentFile only via `DocumentFile(uri: uri).get()`
180+
///doc = await DocumentFile(uri: filePath).get();
176181
} catch (e) {
177182
exception = _exceptionEntry(e);
178183
}
@@ -183,7 +188,8 @@ class _InitDocumentFileState extends State<InitDocumentFile> {
183188
//4. Update the result
184189
widget.onResult([
185190
MethodApiEntry(
186-
name: 'DocumentFile(uri: $filePath).get()',
191+
//name: DocumentFile(uri: $filePath).get()
192+
name: 'DocumentFile.fromUri($filePath)',
187193
title: exception != null
188194
? exception.title
189195
: 'DocumentFile: ${doc?.name}',

lib/src/data/document_file.dart

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import 'package:docman/docman.dart';
12
import 'package:flutter/material.dart';
23

34
/// A class representing a `DocumentFile` on dart side.
@@ -93,6 +94,16 @@ class DocumentFile {
9394
canThumbnail: map['canThumbnail'] as bool,
9495
);
9596

97+
/// Instantiates a [DocumentFile] from a Content URI or a File path.
98+
///
99+
/// Same as `DocumentFile(uri: uri).get()`, just syntactic sugar.
100+
///
101+
/// **Note**: Or you can use old method `DocumentFile(uri: uri).get()` to get the `DocumentFile` instance.
102+
///
103+
/// Returns a [DocumentFile] instance or `null` if the document is not available.
104+
static Future<DocumentFile?> fromUri(String uri) =>
105+
DocumentFile(uri: uri).get();
106+
96107
/// Checks if the document is a directory.
97108
bool get isDirectory => type == 'directory';
98109

0 commit comments

Comments
 (0)