Skip to content

Commit bb9ea89

Browse files
committed
(#110) Update example project to cover openDocument API
1 parent 3ad5b54 commit bb9ea89

File tree

4 files changed

+228
-97
lines changed

4 files changed

+228
-97
lines changed

example/lib/screens/file_explorer/file_explorer_card.dart

Lines changed: 3 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,13 @@ import 'dart:io';
33
import 'dart:math';
44
import 'dart:typed_data';
55

6-
import 'package:fl_toast/fl_toast.dart';
76
import 'package:flutter/material.dart';
8-
import 'package:flutter/services.dart';
97
import 'package:shared_storage/shared_storage.dart';
108

11-
import '../../theme/spacing.dart';
129
import '../../utils/apply_if_not_null.dart';
1310
import '../../utils/confirm_decorator.dart';
1411
import '../../utils/disabled_text_style.dart';
12+
import '../../utils/document_file_utils.dart';
1513
import '../../utils/format_bytes.dart';
1614
import '../../utils/inline_span.dart';
1715
import '../../utils/mime_types.dart';
@@ -241,7 +239,7 @@ class _FileExplorerCardState extends State<FileExplorerCard> {
241239
}
242240

243241
Widget _buildOpenWithButton() =>
244-
Button('Open with', onTap: _openFileWithExternalApp);
242+
Button('Open with', onTap: _currentUri.openWithExternalApp);
245243

246244
Widget _buildDocumentSimplifiedTile() {
247245
return ListTile(
@@ -319,60 +317,6 @@ class _FileExplorerCardState extends State<FileExplorerCard> {
319317

320318
String get _mimeTypeOrEmpty => _file.type ?? '';
321319

322-
Future<void> _showFileContents() async {
323-
if (_isDirectory) return;
324-
325-
const k10mb = 1024 * 1024 * 10;
326-
327-
if (!_mimeTypeOrEmpty.startsWith(kTextMime) &&
328-
!_mimeTypeOrEmpty.startsWith(kImageMime)) {
329-
if (_mimeTypeOrEmpty == kApkMime) {
330-
return showTextToast(
331-
text:
332-
'Requesting to install a package (.apk) is not currently supported, to request this feature open an issue at github.com/alexrintt/shared-storage/issues',
333-
context: context,
334-
);
335-
}
336-
337-
return _openFileWithExternalApp();
338-
}
339-
340-
// Too long, will take too much time to read
341-
if (_sizeInBytes > k10mb) {
342-
return showTextToast(
343-
text: 'File too long to open',
344-
context: context,
345-
);
346-
}
347-
348-
content = await getDocumentContent(_file.uri);
349-
350-
if (content != null) {
351-
final isImage = _mimeTypeOrEmpty.startsWith(kImageMime);
352-
353-
await showModalBottomSheet(
354-
context: context,
355-
builder: (context) {
356-
if (isImage) {
357-
return Image.memory(content!);
358-
}
359-
360-
final contentAsString = String.fromCharCodes(content!);
361-
362-
final fileIsEmpty = contentAsString.isEmpty;
363-
364-
return Container(
365-
padding: k8dp.all,
366-
child: Text(
367-
fileIsEmpty ? 'This file is empty' : contentAsString,
368-
style: fileIsEmpty ? disabledTextStyle() : null,
369-
),
370-
);
371-
},
372-
);
373-
}
374-
}
375-
376320
Future<void> _deleteDocument() async {
377321
final deleted = await delete(_currentUri);
378322

@@ -436,24 +380,6 @@ class _FileExplorerCardState extends State<FileExplorerCard> {
436380
}
437381
}
438382

439-
Future<void> _openFileWithExternalApp() async {
440-
final uri = _currentUri;
441-
442-
try {
443-
final launched = await openDocumentFile(uri);
444-
445-
if (launched ?? false) {
446-
print('Successfully opened $uri');
447-
} else {
448-
print('Failed to launch $uri');
449-
}
450-
} on PlatformException {
451-
print(
452-
"There's no activity associated with the file type of this Uri: $uri",
453-
);
454-
}
455-
}
456-
457383
Future<void> _openDirectory() async {
458384
if (_isDirectory) {
459385
_openFolderFileListPage(_file.uri);
@@ -463,7 +389,7 @@ class _FileExplorerCardState extends State<FileExplorerCard> {
463389
@override
464390
Widget build(BuildContext context) {
465391
return SimpleCard(
466-
onTap: _isDirectory ? _openDirectory : _showFileContents,
392+
onTap: _isDirectory ? _openDirectory : () => _file.showContents(context),
467393
children: [
468394
if (_expanded) ...[
469395
_buildThumbnail(size: 50),

example/lib/screens/granted_uris/granted_uri_card.dart

Lines changed: 88 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
1+
import 'package:fl_toast/fl_toast.dart';
12
import 'package:flutter/material.dart';
23
import 'package:shared_storage/shared_storage.dart';
34

45
import '../../theme/spacing.dart';
6+
import '../../utils/disabled_text_style.dart';
7+
import '../../utils/document_file_utils.dart';
58
import '../../widgets/buttons.dart';
69
import '../../widgets/key_value_text.dart';
710
import '../../widgets/simple_card.dart';
11+
import '../file_explorer/file_explorer_card.dart';
812
import '../file_explorer/file_explorer_page.dart';
913

1014
class GrantedUriCard extends StatefulWidget {
@@ -55,19 +59,65 @@ class _GrantedUriCardState extends State<GrantedUriCard> {
5559
);
5660
}
5761

62+
List<Widget> _getTreeAvailableOptions() {
63+
return [
64+
ActionButton(
65+
'Create sample file',
66+
onTap: () => _appendSampleFile(
67+
widget.permissionUri.uri,
68+
),
69+
),
70+
ActionButton(
71+
'Open tree here',
72+
onTap: () => openDocumentTree(initialUri: widget.permissionUri.uri),
73+
)
74+
];
75+
}
76+
77+
DocumentFile? documentFile;
78+
bool loading = false;
79+
String? error;
80+
81+
Future<void> _loadDocumentFile() async {
82+
loading = true;
83+
setState(() {});
84+
85+
documentFile = await widget.permissionUri.uri.toDocumentFile();
86+
loading = false;
87+
88+
if (mounted) setState(() {});
89+
}
90+
91+
Future<void> _showDocumentFileContents() async {
92+
try {
93+
final documentFile = await widget.permissionUri.uri.toDocumentFile();
94+
95+
if (mounted) documentFile?.showContents(context);
96+
} catch (e) {
97+
error = e.toString();
98+
}
99+
}
100+
101+
List<Widget> _getDocumentAvailableOptions() {
102+
return [
103+
ActionButton(
104+
'Open document',
105+
onTap: _showDocumentFileContents,
106+
),
107+
ActionButton(
108+
'Load extra document data linked to this permission',
109+
onTap: _loadDocumentFile,
110+
),
111+
];
112+
}
113+
58114
Widget _buildAvailableActions() {
59115
return Wrap(
60116
children: [
61-
ActionButton(
62-
'Create Sample File',
63-
onTap: () => _appendSampleFile(
64-
widget.permissionUri.uri,
65-
),
66-
),
67-
ActionButton(
68-
'Open Tree Here',
69-
onTap: () => openDocumentTree(initialUri: widget.permissionUri.uri),
70-
),
117+
if (widget.permissionUri.isTreeDocumentFile)
118+
..._getTreeAvailableOptions()
119+
else
120+
..._getDocumentAvailableOptions(),
71121
Padding(padding: k2dp.all),
72122
DangerButton(
73123
'Revoke',
@@ -86,17 +136,44 @@ class _GrantedUriCardState extends State<GrantedUriCard> {
86136
'isReadPermission': '${widget.permissionUri.isReadPermission}',
87137
'persistedTime': '${widget.permissionUri.persistedTime}',
88138
'uri': Uri.decodeFull('${widget.permissionUri.uri}'),
139+
'isTreeDocumentFile': '${widget.permissionUri.isTreeDocumentFile}',
89140
},
90141
);
91142
}
92143

93144
@override
94145
Widget build(BuildContext context) {
95146
return SimpleCard(
96-
onTap: _openListFilesPage,
147+
onTap: widget.permissionUri.isTreeDocumentFile
148+
? _openListFilesPage
149+
: _showDocumentFileContents,
97150
children: [
151+
Padding(
152+
padding: k2dp.all.copyWith(top: k8dp, bottom: k8dp),
153+
child: Icon(
154+
widget.permissionUri.isTreeDocumentFile
155+
? Icons.folder
156+
: Icons.file_copy_sharp,
157+
color: disabledColor(),
158+
),
159+
),
98160
_buildGrantedUriMetadata(),
99161
_buildAvailableActions(),
162+
if (loading)
163+
const SizedBox(
164+
height: 20,
165+
width: 20,
166+
child: CircularProgressIndicator(),
167+
)
168+
else if (error != null)
169+
Text('Error was thrown: $error')
170+
else if (documentFile != null)
171+
FileExplorerCard(
172+
documentFile: documentFile!,
173+
didUpdateDocument: (updatedDocumentFile) {
174+
documentFile = updatedDocumentFile;
175+
},
176+
)
100177
],
101178
);
102179
}

example/lib/screens/granted_uris/granted_uris_page.dart

Lines changed: 47 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
22
import 'package:shared_storage/shared_storage.dart';
33

44
import '../../theme/spacing.dart';
5+
import '../../utils/disabled_text_style.dart';
56
import '../../widgets/light_text.dart';
67
import 'granted_uri_card.dart';
78

@@ -13,7 +14,13 @@ class GrantedUrisPage extends StatefulWidget {
1314
}
1415

1516
class _GrantedUrisPageState extends State<GrantedUrisPage> {
16-
List<UriPermission>? persistedPermissionUris;
17+
List<UriPermission>? __persistedPermissionUris;
18+
List<UriPermission>? get _persistedPermissionUris {
19+
if (__persistedPermissionUris == null) return null;
20+
21+
return List.from(__persistedPermissionUris!)
22+
..sort((a, z) => z.persistedTime - a.persistedTime);
23+
}
1724

1825
@override
1926
void initState() {
@@ -23,7 +30,7 @@ class _GrantedUrisPageState extends State<GrantedUrisPage> {
2330
}
2431

2532
Future<void> _loadPersistedUriPermissions() async {
26-
persistedPermissionUris = await persistedUriPermissions();
33+
__persistedPermissionUris = await persistedUriPermissions();
2734

2835
if (mounted) setState(() => {});
2936
}
@@ -41,6 +48,20 @@ class _GrantedUrisPageState extends State<GrantedUrisPage> {
4148
await _loadPersistedUriPermissions();
4249
}
4350

51+
Future<void> _openDocument() async {
52+
const kDownloadsFolder =
53+
'content://com.android.externalstorage.documents/tree/primary%3ADownloads/document/primary%3ADownloads';
54+
55+
final List<Uri>? selectedDocumentUris = await openDocument(
56+
initialUri: Uri.parse(kDownloadsFolder),
57+
multiple: true,
58+
);
59+
60+
if (selectedDocumentUris == null) return;
61+
62+
await _loadPersistedUriPermissions();
63+
}
64+
4465
Widget _buildNoFolderAllowedYetWarning() {
4566
return Padding(
4667
padding: k8dp.all,
@@ -66,22 +87,39 @@ class _GrantedUrisPageState extends State<GrantedUrisPage> {
6687
delegate: SliverChildListDelegate(
6788
[
6889
Center(
69-
child: TextButton(
70-
onPressed: _openDocumentTree,
71-
child: const Text('New allowed folder'),
90+
child: Wrap(
91+
alignment: WrapAlignment.center,
92+
crossAxisAlignment: WrapCrossAlignment.center,
93+
runAlignment: WrapAlignment.center,
94+
children: [
95+
TextButton(
96+
onPressed: _openDocumentTree,
97+
child: const Text('New allowed folder'),
98+
),
99+
const Padding(padding: EdgeInsets.all(k2dp)),
100+
TextButton(
101+
onPressed: _openDocument,
102+
child: const Text('New allowed files'),
103+
),
104+
],
72105
),
73106
),
74-
if (persistedPermissionUris != null)
75-
if (persistedPermissionUris!.isEmpty)
107+
if (_persistedPermissionUris != null)
108+
if (_persistedPermissionUris!.isEmpty)
76109
_buildNoFolderAllowedYetWarning()
77110
else
78-
for (final permissionUri in persistedPermissionUris!)
111+
for (final permissionUri in _persistedPermissionUris!)
79112
GrantedUriCard(
80113
permissionUri: permissionUri,
81114
onChange: _loadPersistedUriPermissions,
82115
)
83116
else
84-
const Text('Loading...'),
117+
Center(
118+
child: Text(
119+
'Loading...',
120+
style: disabledTextStyle(),
121+
),
122+
),
85123
],
86124
),
87125
),

0 commit comments

Comments
 (0)