Skip to content

Commit

Permalink
feat: make it possible to filter files by type (#55)
Browse files Browse the repository at this point in the history
Add `type` property to `FilePickerSheet`, which controlls pickable file
type.

For iOS, pass `FileType.media` to `FilePicker.platform.pickFiles()` by
default.
This is because if `type` is `FileType.any`, iOS opens "Files" app,
which is inconvenient for basic usage.
With `FileType.media`, it opens "Photos" app, where users can find their
images and videos.

Close #54
  • Loading branch information
poppingmoon authored Apr 6, 2024
1 parent 2284351 commit 95c082b
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 42 deletions.
96 changes: 58 additions & 38 deletions lib/view/page/drive_page.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'package:collection/collection.dart';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:go_router/go_router.dart';
Expand Down Expand Up @@ -27,12 +28,14 @@ class DrivePage extends HookConsumerWidget {
this.selectFile = false,
this.selectFiles = false,
this.selectFolder = false,
this.type = FileType.any,
});

final Account account;
final bool selectFile;
final bool selectFiles;
final bool selectFolder;
final FileType type;

static const itemMaxCrossAxisExtent = 400.0;

Expand Down Expand Up @@ -301,45 +304,62 @@ class DrivePage extends HookConsumerWidget {
case AsyncValue(
valueOrNull: PaginationState(items: final files)
))
SliverGrid.builder(
gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: itemMaxCrossAxisExtent,
),
itemCount: files.length,
itemBuilder: (context, index) {
final file = files[index];
final isSelected =
selectedFiles.any((e) => e.id == file.id);
return DriveFileWidget(
account: account,
file: file,
isSelected: isSelected,
onTap: () {
if (selectFile) {
context.pop(file);
} else if (isSelecting) {
if (isSelected) {
ref
.read(
selectedDriveFilesNotifierProvider.notifier,
)
.remove(file.id);
} else {
ref
.read(
selectedDriveFilesNotifierProvider.notifier,
)
.add(file);
}
} else {
context.push(
'/$account/drive/file/${folderId != null ? '$folderId/' : ''}${file.id}',
);
}
Builder(
builder: (context) {
final filtered = files.where(
(file) => switch (type) {
FileType.media =>
file.type.startsWith(RegExp('image|video')),
FileType.image => file.type.startsWith('image'),
FileType.video => file.type.startsWith('video'),
FileType.audio => file.type.startsWith('audio'),
FileType.any || FileType.custom => true,
},
);
return SliverGrid.builder(
gridDelegate:
const SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: itemMaxCrossAxisExtent,
),
itemCount: filtered.length,
itemBuilder: (context, index) {
final file = filtered.elementAt(index);
final isSelected =
selectedFiles.any((e) => e.id == file.id);
return DriveFileWidget(
account: account,
file: file,
isSelected: isSelected,
onTap: () {
if (selectFile) {
context.pop(file);
} else if (isSelecting) {
if (isSelected) {
ref
.read(
selectedDriveFilesNotifierProvider
.notifier,
)
.remove(file.id);
} else {
ref
.read(
selectedDriveFilesNotifierProvider
.notifier,
)
.add(file);
}
} else {
context.push(
'/$account/drive/file/${folderId != null ? '$folderId/' : ''}${file.id}',
);
}
},
onLongPress: () => ref
.read(selectedDriveFilesNotifierProvider.notifier)
.add(file),
);
},
onLongPress: () => ref
.read(selectedDriveFilesNotifierProvider.notifier)
.add(file),
);
},
),
Expand Down
6 changes: 5 additions & 1 deletion lib/view/page/image_page.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'dart:typed_data';
import 'dart:ui';

import 'package:file_picker/file_picker.dart';
import 'package:flex_color_picker/flex_color_picker.dart';
import 'package:flutter/material.dart' hide Image;
import 'package:flutter_hooks/flutter_hooks.dart';
Expand Down Expand Up @@ -409,7 +410,10 @@ class ImagePage extends HookConsumerWidget {
case _Modes.image:
final file = await showModalBottomSheet<PostFile>(
context: context,
builder: (context) => FilePickerSheet(account: account),
builder: (context) => FilePickerSheet(
account: account,
type: FileType.image,
),
clipBehavior: Clip.hardEdge,
);
if (file == null) return;
Expand Down
6 changes: 5 additions & 1 deletion lib/view/page/settings/profile_page.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'package:file_picker/file_picker.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
Expand Down Expand Up @@ -45,7 +46,10 @@ class ProfilePage extends HookConsumerWidget {
}) async {
final result = await showModalBottomSheet<PostFile>(
context: ref.context,
builder: (context) => FilePickerSheet(account: account),
builder: (context) => FilePickerSheet(
account: account,
type: FileType.image,
),
clipBehavior: Clip.hardEdge,
);
if (result == null) return null;
Expand Down
4 changes: 4 additions & 0 deletions lib/view/widget/drive_create_sheet.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'package:file_picker/file_picker.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:go_router/go_router.dart';
Expand Down Expand Up @@ -28,6 +29,9 @@ class DriveCreateSheet extends HookConsumerWidget {

Future<void> _upload(WidgetRef ref, bool keepOriginal) async {
final result = await FilePicker.platform.pickFiles(
type: defaultTargetPlatform == TargetPlatform.iOS
? FileType.media
: FileType.any,
allowMultiple: true,
);
if (result == null || result.files.isEmpty) return;
Expand Down
13 changes: 11 additions & 2 deletions lib/view/widget/file_picker_sheet.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'package:file_picker/file_picker.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
Expand All @@ -14,10 +15,12 @@ class FilePickerSheet extends ConsumerWidget {
const FilePickerSheet({
super.key,
required this.account,
this.type,
this.allowMultiple = false,
});

final Account account;
final FileType? type;
final bool allowMultiple;

@override
Expand All @@ -29,8 +32,12 @@ class FilePickerSheet extends ConsumerWidget {
leading: const Icon(Icons.upload),
title: Text(t.aria.fromDevice),
onTap: () async {
final result = await FilePicker.platform
.pickFiles(allowMultiple: allowMultiple);
final result = await FilePicker.platform.pickFiles(
type: defaultTargetPlatform == TargetPlatform.iOS && type == null
? FileType.media
: type ?? FileType.any,
allowMultiple: allowMultiple,
);
if (!context.mounted) return;
if (result case FilePickerResult(:final files)) {
if (allowMultiple) {
Expand Down Expand Up @@ -63,6 +70,7 @@ class FilePickerSheet extends ConsumerWidget {
builder: (context) => DrivePage(
account: account,
selectFiles: true,
type: type ?? FileType.any,
),
);
if (!context.mounted) return;
Expand All @@ -79,6 +87,7 @@ class FilePickerSheet extends ConsumerWidget {
builder: (context) => DrivePage(
account: account,
selectFile: true,
type: type ?? FileType.any,
),
);
if (!context.mounted) return;
Expand Down

0 comments on commit 95c082b

Please sign in to comment.