Skip to content

Commit

Permalink
Merge pull request #1103 from nextcloud/feature/nextcloud/webdav-pathuri
Browse files Browse the repository at this point in the history
  • Loading branch information
provokateurin authored Nov 13, 2023
2 parents 1f45ff4 + eade429 commit d720dc8
Show file tree
Hide file tree
Showing 19 changed files with 482 additions and 237 deletions.
26 changes: 13 additions & 13 deletions packages/neon/neon_files/lib/blocs/browser.dart
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
part of '../neon_files.dart';

abstract interface class FilesBrowserBlocEvents {
void setPath(final List<String> path);
void setPath(final PathUri uri);

void createFolder(final List<String> path);
void createFolder(final PathUri uri);
}

abstract interface class FilesBrowserBlocStates {
BehaviorSubject<Result<List<WebDavFile>>> get files;

BehaviorSubject<List<String>> get path;
BehaviorSubject<PathUri> get uri;
}

class FilesBrowserBloc extends InteractiveBloc implements FilesBrowserBlocEvents, FilesBrowserBlocStates {
FilesBrowserBloc(
this.options,
this.account, {
final List<String>? initialPath,
final PathUri? initialPath,
}) {
if (initialPath != null) {
path.add(initialPath);
uri.add(initialPath);
}

unawaited(refresh());
Expand All @@ -31,24 +31,24 @@ class FilesBrowserBloc extends InteractiveBloc implements FilesBrowserBlocEvents
@override
void dispose() {
unawaited(files.close());
unawaited(path.close());
unawaited(uri.close());
super.dispose();
}

@override
BehaviorSubject<Result<List<WebDavFile>>> files = BehaviorSubject<Result<List<WebDavFile>>>();

@override
BehaviorSubject<List<String>> path = BehaviorSubject<List<String>>.seeded([]);
BehaviorSubject<PathUri> uri = BehaviorSubject.seeded(PathUri.cwd());

@override
Future<void> refresh() async {
await RequestManager.instance.wrapWebDav<List<WebDavFile>>(
account.id,
'files-${path.value.join('/')}',
'files-${uri.value.path}',
files,
() => account.client.webdav.propfind(
Uri(pathSegments: path.value),
uri.value,
prop: WebDavPropWithoutValues.fromBools(
davgetcontenttype: true,
davgetetag: true,
Expand All @@ -65,13 +65,13 @@ class FilesBrowserBloc extends InteractiveBloc implements FilesBrowserBlocEvents
}

@override
void setPath(final List<String> p) {
path.add(p);
void setPath(final PathUri uri) {
this.uri.add(uri);
unawaited(refresh());
}

@override
void createFolder(final List<String> path) {
wrapAction(() async => account.client.webdav.mkcol(Uri(pathSegments: path)));
void createFolder(final PathUri uri) {
wrapAction(() async => account.client.webdav.mkcol(uri));
}
}
84 changes: 42 additions & 42 deletions packages/neon/neon_files/lib/blocs/files.dart
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
part of '../neon_files.dart';

abstract interface class FilesBlocEvents {
void uploadFile(final List<String> path, final String localPath);
void uploadFile(final PathUri uri, final String localPath);

void syncFile(final List<String> path);
void syncFile(final PathUri uri);

void openFile(final List<String> path, final String etag, final String? mimeType);
void openFile(final PathUri uri, final String etag, final String? mimeType);

void shareFileNative(final List<String> path, final String etag);
void shareFileNative(final PathUri uri, final String etag);

void delete(final List<String> path);
void delete(final PathUri uri);

void rename(final List<String> path, final String name);
void rename(final PathUri uri, final String name);

void move(final List<String> path, final List<String> destination);
void move(final PathUri uri, final PathUri destination);

void copy(final List<String> path, final List<String> destination);
void copy(final PathUri uri, final PathUri destination);

void addFavorite(final List<String> path);
void addFavorite(final PathUri uri);

void removeFavorite(final List<String> path);
void removeFavorite(final PathUri uri);
}

abstract interface class FilesBlocStates {
Expand Down Expand Up @@ -58,35 +58,35 @@ class FilesBloc extends InteractiveBloc implements FilesBlocEvents, FilesBlocSta
BehaviorSubject<List<FilesTask>> tasks = BehaviorSubject<List<FilesTask>>.seeded([]);

@override
void addFavorite(final List<String> path) {
void addFavorite(final PathUri uri) {
wrapAction(
() async => account.client.webdav.proppatch(
Uri(pathSegments: path),
uri,
set: WebDavProp(ocfavorite: 1),
),
);
}

@override
void copy(final List<String> path, final List<String> destination) {
wrapAction(() async => account.client.webdav.copy(Uri(pathSegments: path), Uri(pathSegments: destination)));
void copy(final PathUri uri, final PathUri destination) {
wrapAction(() async => account.client.webdav.copy(uri, destination));
}

@override
void delete(final List<String> path) {
wrapAction(() async => account.client.webdav.delete(Uri(pathSegments: path)));
void delete(final PathUri uri) {
wrapAction(() async => account.client.webdav.delete(uri));
}

@override
void move(final List<String> path, final List<String> destination) {
wrapAction(() async => account.client.webdav.move(Uri(pathSegments: path), Uri(pathSegments: destination)));
void move(final PathUri uri, final PathUri destination) {
wrapAction(() async => account.client.webdav.move(uri, destination));
}

@override
void openFile(final List<String> path, final String etag, final String? mimeType) {
void openFile(final PathUri uri, final String etag, final String? mimeType) {
wrapAction(
() async {
final file = await _cacheFile(path, etag);
final file = await _cacheFile(uri, etag);

final result = await OpenFile.open(file.path, type: mimeType);
if (result.type != ResultType.done) {
Expand All @@ -98,10 +98,10 @@ class FilesBloc extends InteractiveBloc implements FilesBlocEvents, FilesBlocSta
}

@override
void shareFileNative(final List<String> path, final String etag) {
void shareFileNative(final PathUri uri, final String etag) {
wrapAction(
() async {
final file = await _cacheFile(path, etag);
final file = await _cacheFile(uri, etag);

await Share.shareXFiles([XFile(file.path)]);
},
Expand All @@ -115,52 +115,52 @@ class FilesBloc extends InteractiveBloc implements FilesBlocEvents, FilesBlocSta
}

@override
void removeFavorite(final List<String> path) {
void removeFavorite(final PathUri uri) {
wrapAction(
() async => account.client.webdav.proppatch(
Uri(pathSegments: path),
uri,
set: WebDavProp(ocfavorite: 0),
),
);
}

@override
void rename(final List<String> path, final String name) {
void rename(final PathUri uri, final String name) {
wrapAction(
() async => account.client.webdav.move(
Uri(pathSegments: path),
Uri(pathSegments: List.from(path)..last = name),
uri,
uri.rename(name),
),
);
}

@override
void syncFile(final List<String> path) {
void syncFile(final PathUri uri) {
wrapAction(
() async {
final file = File(
p.join(
p.joinAll([
await NeonPlatform.instance.userAccessibleAppDataPath,
account.humanReadableID,
'files',
path.join(Platform.pathSeparator),
),
...uri.pathSegments,
]),
);
if (!file.parent.existsSync()) {
file.parent.createSync(recursive: true);
}
await _downloadFile(path, file);
await _downloadFile(uri, file);
},
disableTimeout: true,
);
}

@override
void uploadFile(final List<String> path, final String localPath) {
void uploadFile(final PathUri uri, final String localPath) {
wrapAction(
() async {
final task = FilesUploadTask(
path: path,
uri: uri,
file: File(localPath),
);
tasks.add(tasks.value..add(task));
Expand All @@ -171,27 +171,27 @@ class FilesBloc extends InteractiveBloc implements FilesBlocEvents, FilesBlocSta
);
}

Future<File> _cacheFile(final List<String> path, final String etag) async {
Future<File> _cacheFile(final PathUri uri, final String etag) async {
final cacheDir = await getApplicationCacheDirectory();
final file = File(p.join(cacheDir.path, 'files', etag.replaceAll('"', ''), path.last));
final file = File(p.join(cacheDir.path, 'files', etag.replaceAll('"', ''), uri.name));

if (!file.existsSync()) {
debugPrint('Downloading ${Uri(pathSegments: path)} since it does not exist');
debugPrint('Downloading $uri since it does not exist');
if (!file.parent.existsSync()) {
await file.parent.create(recursive: true);
}
await _downloadFile(path, file);
await _downloadFile(uri, file);
}

return file;
}

Future<void> _downloadFile(
final List<String> path,
final PathUri uri,
final File file,
) async {
final task = FilesDownloadTask(
path: path,
uri: uri,
file: file,
);
tasks.add(tasks.value..add(task));
Expand All @@ -200,12 +200,12 @@ class FilesBloc extends InteractiveBloc implements FilesBlocEvents, FilesBlocSta
}

FilesBrowserBloc getNewFilesBrowserBloc({
final List<String>? initialPath,
final PathUri? initialUri,
}) =>
FilesBrowserBloc(
options,
account,
initialPath: initialPath,
initialPath: initialUri,
);

void _downloadParallelismListener() {
Expand Down
11 changes: 7 additions & 4 deletions packages/neon/neon_files/lib/dialogs/choose_create.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class FilesChooseCreateDialog extends StatefulWidget {
});

final FilesBloc bloc;
final List<String> basePath;
final PathUri basePath;

@override
State<FilesChooseCreateDialog> createState() => _FilesChooseCreateDialogState();
Expand Down Expand Up @@ -43,7 +43,10 @@ class _FilesChooseCreateDialogState extends State<FilesChooseCreateDialog> {
}
}
}
widget.bloc.uploadFile([...widget.basePath, p.basename(file.path)], file.path);
widget.bloc.uploadFile(
widget.basePath.join(PathUri.parse(p.basename(file.path))),
file.path,
);
}

@override
Expand Down Expand Up @@ -104,12 +107,12 @@ class _FilesChooseCreateDialogState extends State<FilesChooseCreateDialog> {
onTap: () async {
Navigator.of(context).pop();

final result = await showDialog<List<String>>(
final result = await showDialog<String>(
context: context,
builder: (final context) => const FilesCreateFolderDialog(),
);
if (result != null) {
widget.bloc.browser.createFolder([...widget.basePath, ...result]);
widget.bloc.browser.createFolder(widget.basePath.join(PathUri.parse(result)));
}
},
),
Expand Down
16 changes: 8 additions & 8 deletions packages/neon/neon_files/lib/dialogs/choose_folder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class FilesChooseFolderDialog extends StatelessWidget {
final FilesBrowserBloc bloc;
final FilesBloc filesBloc;

final List<String> originalPath;
final PathUri originalPath;

@override
Widget build(final BuildContext context) => AlertDialog(
Expand All @@ -28,29 +28,29 @@ class FilesChooseFolderDialog extends StatelessWidget {
mode: FilesBrowserMode.selectDirectory,
),
),
StreamBuilder<List<String>>(
stream: bloc.path,
builder: (final context, final pathSnapshot) => pathSnapshot.hasData
StreamBuilder<PathUri>(
stream: bloc.uri,
builder: (final context, final uriSnapshot) => uriSnapshot.hasData
? Container(
margin: const EdgeInsets.all(10),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
ElevatedButton(
onPressed: () async {
final result = await showDialog<List<String>>(
final result = await showDialog<String>(
context: context,
builder: (final context) => const FilesCreateFolderDialog(),
);
if (result != null) {
bloc.createFolder([...pathSnapshot.requireData, ...result]);
bloc.createFolder(uriSnapshot.requireData.join(PathUri.parse(result)));
}
},
child: Text(FilesLocalizations.of(context).folderCreate),
),
ElevatedButton(
onPressed: !(const ListEquality<String>().equals(originalPath, pathSnapshot.data))
? () => Navigator.of(context).pop(pathSnapshot.data)
onPressed: originalPath != uriSnapshot.requireData
? () => Navigator.of(context).pop(uriSnapshot.requireData)
: null,
child: Text(FilesLocalizations.of(context).folderChoose),
),
Expand Down
2 changes: 1 addition & 1 deletion packages/neon/neon_files/lib/dialogs/create_folder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class _FilesCreateFolderDialogState extends State<FilesCreateFolderDialog> {

void submit() {
if (formKey.currentState!.validate()) {
Navigator.of(context).pop(controller.text.split('/'));
Navigator.of(context).pop(controller.text);
}
}

Expand Down
Loading

0 comments on commit d720dc8

Please sign in to comment.