Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(nextcloud,neon_files): Introduce PathUri for WebDAV path handling #1103

Merged
merged 1 commit into from
Nov 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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