part of '../neon_files.dart'; @immutable class FilesSync implements SyncImplementation { const FilesSync(); @override String get appId => AppIDs.files; @override Future getSources(final Account account, final FilesSyncMapping mapping) async { // This shouldn't be necessary, but it sadly is because of https://github.com/flutter/flutter/issues/25659. // Alternative would be to use https://pub.dev/packages/shared_storage, // but to be efficient we'd need https://github.com/alexrintt/shared-storage/issues/91 // or copy the files to the app cache (which is also not optimal). if (Platform.isAndroid && !await Permission.manageExternalStorage.request().isGranted) { throw const MissingPermissionException(Permission.manageExternalStorage); } return FilesSyncSources( account.client, mapping.remotePath, mapping.localPath, ); } @override Map serializeMapping(final FilesSyncMapping mapping) => mapping.toJson(); @override FilesSyncMapping deserializeMapping(final Map json) => FilesSyncMapping.fromJson(json); @override Future addMapping(final BuildContext context, final Account account) async { final accountsBloc = NeonProvider.of(context); final appsBloc = accountsBloc.getAppsBlocFor(account); final filesBloc = appsBloc.getAppBlocByID(AppIDs.files)! as FilesBloc; final filesBrowserBloc = filesBloc.getNewFilesBrowserBloc(); final remotePath = await showDialog( context: context, builder: (final context) => FilesChooseFolderDialog( bloc: filesBrowserBloc, filesBloc: filesBloc, originalPath: PathUri.cwd(), ), ); filesBrowserBloc.dispose(); if (remotePath == null) { return null; } final localPath = await FileUtils.pickDirectory(); if (localPath == null) { return null; } if (!context.mounted) { return null; } return FilesSyncMapping( appId: AppIDs.files, accountId: account.id, remotePath: remotePath, localPath: Directory(localPath), journal: SyncJournal(), ); } @override String getMappingDisplayTitle(final FilesSyncMapping mapping) => mapping.remotePath.toString(); @override String getMappingDisplaySubtitle(final FilesSyncMapping mapping) => mapping.localPath.path; @override String getMappingId(final FilesSyncMapping mapping) => '${Uri.encodeComponent(mapping.remotePath.toString())}-${Uri.encodeComponent(mapping.localPath.path)}'; @override Widget getConflictDetailsLocal(final BuildContext context, final FileSystemEntity object) { final stat = object.statSync(); return FilesFileTile( showFullPath: true, filesBloc: NeonProvider.of(context), details: FileDetails( uri: PathUri.parse(object.path), size: stat.size, etag: '', mimeType: '', lastModified: stat.modified, hasPreview: false, isFavorite: false, ), ); } @override Widget getConflictDetailsRemote(final BuildContext context, final WebDavFile object) => FilesFileTile( showFullPath: true, filesBloc: NeonProvider.of(context), details: FileDetails.fromWebDav( file: object, ), ); }