Browse Source

feat(neon_files): enable hiding files starting with a '.'

Signed-off-by: Nikolas Rimikis <rimikis.nikolas@gmail.com>
pull/604/head
Nikolas Rimikis 1 year ago
parent
commit
c4d38589a7
No known key found for this signature in database
GPG Key ID: 85ED1DE9786A4FF2
  1. 1
      packages/neon/neon_files/lib/l10n/en.arb
  2. 6
      packages/neon/neon_files/lib/l10n/localizations.dart
  3. 3
      packages/neon/neon_files/lib/l10n/localizations_en.dart
  4. 10
      packages/neon/neon_files/lib/options.dart
  5. 196
      packages/neon/neon_files/lib/widgets/browser_view.dart
  6. 11
      packages/nextcloud/lib/src/webdav/file.dart
  7. 1
      packages/nextcloud/pubspec.yaml

1
packages/neon/neon_files/lib/l10n/en.arb

@ -77,6 +77,7 @@
"optionsFilesSortPropertyModifiedDate": "Last modified", "optionsFilesSortPropertyModifiedDate": "Last modified",
"optionsFilesSortPropertySize": "Size", "optionsFilesSortPropertySize": "Size",
"optionsFilesSortOrder": "Sort order of files", "optionsFilesSortOrder": "Sort order of files",
"optionsShowHiddenFiles": "Show hidden files",
"optionsShowPreviews": "Show previews for files", "optionsShowPreviews": "Show previews for files",
"optionsUploadQueueParallelism": "Upload queue parallelism", "optionsUploadQueueParallelism": "Upload queue parallelism",
"optionsDownloadQueueParallelism": "Download queue parallelism", "optionsDownloadQueueParallelism": "Download queue parallelism",

6
packages/neon/neon_files/lib/l10n/localizations.dart

@ -305,6 +305,12 @@ abstract class AppLocalizations {
/// **'Sort order of files'** /// **'Sort order of files'**
String get optionsFilesSortOrder; String get optionsFilesSortOrder;
/// No description provided for @optionsShowHiddenFiles.
///
/// In en, this message translates to:
/// **'Show hidden files'**
String get optionsShowHiddenFiles;
/// No description provided for @optionsShowPreviews. /// No description provided for @optionsShowPreviews.
/// ///
/// In en, this message translates to: /// In en, this message translates to:

3
packages/neon/neon_files/lib/l10n/localizations_en.dart

@ -122,6 +122,9 @@ class AppLocalizationsEn extends AppLocalizations {
@override @override
String get optionsFilesSortOrder => 'Sort order of files'; String get optionsFilesSortOrder => 'Sort order of files';
@override
String get optionsShowHiddenFiles => 'Show hidden files';
@override @override
String get optionsShowPreviews => 'Show previews for files'; String get optionsShowPreviews => 'Show previews for files';

10
packages/neon/neon_files/lib/options.dart

@ -8,6 +8,7 @@ class FilesAppSpecificOptions extends NextcloudAppOptions {
super.options = [ super.options = [
filesSortPropertyOption, filesSortPropertyOption,
filesSortBoxOrderOption, filesSortBoxOrderOption,
showHiddenFilesOption,
showPreviewsOption, showPreviewsOption,
uploadQueueParallelism, uploadQueueParallelism,
downloadQueueParallelism, downloadQueueParallelism,
@ -43,6 +44,14 @@ class FilesAppSpecificOptions extends NextcloudAppOptions {
values: sortBoxOrderOptionValues, values: sortBoxOrderOptionValues,
); );
late final showHiddenFilesOption = ToggleOption(
storage: super.storage,
category: generalCategory,
key: 'show-hidden-files',
label: (final context) => AppLocalizations.of(context).optionsShowHiddenFiles,
defaultValue: false,
);
late final showPreviewsOption = ToggleOption( late final showPreviewsOption = ToggleOption(
storage: super.storage, storage: super.storage,
category: generalCategory, category: generalCategory,
@ -117,4 +126,5 @@ enum FilesSortProperty {
name, name,
modifiedDate, modifiedDate,
size, size,
isFolder,
} }

196
packages/neon/neon_files/lib/widgets/browser_view.dart

@ -66,112 +66,116 @@ class _FilesBrowserViewState extends State<FilesBrowserView> {
(FilesSortProperty.isFolder, SortBoxOrder.ascending), (FilesSortProperty.isFolder, SortBoxOrder.ascending),
}, },
input: files.data, input: files.data,
builder: (final context, final sorted) => NeonListView<Widget>( builder: (final context, final sorted) => ValueListenableBuilder(
scrollKey: 'files-${pathSnapshot.requireData.join('/')}', valueListenable: widget.bloc.options.showHiddenFilesOption,
withFloatingActionButton: true, builder: (final context, final showHiddenFiles, final _) => NeonListView<Widget>(
items: [ scrollKey: 'files-${pathSnapshot.requireData.join('/')}',
for (final uploadTask in tasksSnapshot.requireData.whereType<FilesUploadTask>().where( withFloatingActionButton: true,
(final task) => items: [
sorted.where((final file) => _pathMatchesFile(task.path, file.name)).isEmpty, for (final uploadTask in tasksSnapshot.requireData.whereType<FilesUploadTask>().where(
)) ...[ (final task) =>
FileListTile( sorted.where((final file) => _pathMatchesFile(task.path, file.name)).isEmpty,
bloc: widget.filesBloc, )) ...[
browserBloc: widget.bloc, FileListTile(
details: FileDetails.fromUploadTask( bloc: widget.filesBloc,
task: uploadTask, browserBloc: widget.bloc,
details: FileDetails.fromUploadTask(
task: uploadTask,
),
mode: widget.mode,
), ),
mode: widget.mode, ],
), for (final file in sorted) ...[
], if ((widget.mode != FilesBrowserMode.selectDirectory || file.isDirectory) &&
for (final file in sorted) ...[ (!file.isHidden || showHiddenFiles)) ...[
if (widget.mode != FilesBrowserMode.selectDirectory || file.isDirectory) ...[ Builder(
Builder( builder: (final context) {
builder: (final context) { final matchingTask = tasksSnapshot.requireData
final matchingTask = tasksSnapshot.requireData .firstWhereOrNull((final task) => _pathMatchesFile(task.path, file.name));
.firstWhereOrNull((final task) => _pathMatchesFile(task.path, file.name));
final details = matchingTask != null final details = matchingTask != null
? FileDetails.fromTask( ? FileDetails.fromTask(
task: matchingTask, task: matchingTask,
file: file, file: file,
) )
: FileDetails.fromWebDav( : FileDetails.fromWebDav(
file: file, file: file,
path: widget.bloc.path.value, path: widget.bloc.path.value,
); );
return FileListTile( return FileListTile(
bloc: widget.filesBloc, bloc: widget.filesBloc,
browserBloc: widget.bloc, browserBloc: widget.bloc,
details: details, details: details,
mode: widget.mode, mode: widget.mode,
); );
}, },
), ),
],
], ],
], ],
], isLoading: files.isLoading,
isLoading: files.isLoading, error: files.error,
error: files.error, onRefresh: widget.bloc.refresh,
onRefresh: widget.bloc.refresh, builder: (final context, final widget) => widget,
builder: (final context, final widget) => widget, topScrollingChildren: [
topScrollingChildren: [ Align(
Align( alignment: Alignment.topLeft,
alignment: Alignment.topLeft, child: Container(
child: Container( margin: const EdgeInsets.symmetric(
margin: const EdgeInsets.symmetric( horizontal: 10,
horizontal: 10, ),
), child: Wrap(
child: Wrap( crossAxisAlignment: WrapCrossAlignment.center,
crossAxisAlignment: WrapCrossAlignment.center, children: <Widget>[
children: <Widget>[ IconButton(
IconButton( padding: EdgeInsets.zero,
padding: EdgeInsets.zero, visualDensity: const VisualDensity(
visualDensity: const VisualDensity( horizontal: VisualDensity.minimumDensity,
horizontal: VisualDensity.minimumDensity, vertical: VisualDensity.minimumDensity,
vertical: VisualDensity.minimumDensity, ),
), tooltip: AppLocalizations.of(context).goToPath(''),
tooltip: AppLocalizations.of(context).goToPath(''), icon: const Icon(
icon: const Icon( Icons.house,
Icons.house, size: 30,
size: 30, ),
), onPressed: () {
onPressed: () { widget.bloc.setPath([]);
widget.bloc.setPath([]);
},
),
for (var i = 0; i < pathSnapshot.requireData.length; i++) ...[
Builder(
builder: (final context) {
final path = pathSnapshot.requireData.sublist(0, i + 1);
return Tooltip(
message: AppLocalizations.of(context).goToPath(path.join('/')),
excludeFromSemantics: true,
child: TextButton(
onPressed: () {
widget.bloc.setPath(path);
},
child: Text(
pathSnapshot.requireData[i],
semanticsLabel: AppLocalizations.of(context).goToPath(path.join('/')),
),
),
);
}, },
), ),
], for (var i = 0; i < pathSnapshot.requireData.length; i++) ...[
] Builder(
.intersperse( builder: (final context) {
const Icon( final path = pathSnapshot.requireData.sublist(0, i + 1);
Icons.keyboard_arrow_right, return Tooltip(
size: 30, message: AppLocalizations.of(context).goToPath(path.join('/')),
excludeFromSemantics: true,
child: TextButton(
onPressed: () {
widget.bloc.setPath(path);
},
child: Text(
pathSnapshot.requireData[i],
semanticsLabel: AppLocalizations.of(context).goToPath(path.join('/')),
),
),
);
},
), ),
) ],
.toList(), ]
.intersperse(
const Icon(
Icons.keyboard_arrow_right,
size: 30,
),
)
.toList(),
),
), ),
), ),
), ],
], ),
), ),
), ),
), ),

11
packages/nextcloud/lib/src/webdav/file.dart

@ -83,12 +83,13 @@ class WebDavFile {
// normalised path (remove trailing slash) // normalised path (remove trailing slash)
final end = path.endsWith('/') ? path.length - 1 : path.length; final end = path.endsWith('/') ? path.length - 1 : path.length;
final segments = Uri.parse(path, 0, end).pathSegments; final segments = Uri.parse(path, 0, end).pathSegments;
if (segments.isNotEmpty) {
return segments.last; return segments.lastOrNull ?? '';
}
return '';
}(); }();
/// Returns if the file is a directory /// Whether the file is hidden.
late final bool isHidden = name.startsWith('.');
/// Whether the file is a directory
late final bool isDirectory = (isCollection ?? false) || path.endsWith('/'); late final bool isDirectory = (isCollection ?? false) || path.endsWith('/');
} }

1
packages/nextcloud/pubspec.yaml

@ -8,6 +8,7 @@ environment:
dependencies: dependencies:
built_collection: ^5.1.1 built_collection: ^5.1.1
built_value: ^8.6.2 built_value: ^8.6.2
collection: ^1.17.2
crypto: ^3.0.3 crypto: ^3.0.3
crypton: ^2.2.0 crypton: ^2.2.0
dynamite_runtime: dynamite_runtime:

Loading…
Cancel
Save