Commit a209d4ad authored by Martin Straka's avatar Martin Straka

Allow to export files to local storage of device

parent 685dabd5
/* /*
* Copyright (C) 2014-2018 CZ.NIC * Copyright (C) 2014-2019 CZ.NIC
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
...@@ -26,6 +26,6 @@ ...@@ -26,6 +26,6 @@
@interface DocumentPickerController : UIViewController @interface DocumentPickerController : UIViewController
- (void)openImportDocumentPicker; - (void)openImportDocumentPicker;
- (void)openExportDocumentPicker:(NSArray<NSURL*>*)exportUrls;
@end @end
/* /*
* Copyright (C) 2014-2018 CZ.NIC * Copyright (C) 2014-2019 CZ.NIC
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
...@@ -21,13 +21,14 @@ ...@@ -21,13 +21,14 @@
* the two. * the two.
*/ */
#include <QString> #include <QList>
#include <QUrl>
#import "ios/src/doc_picker_controller.h" #import "ios/src/doc_picker_controller.h"
// External globals for transporting of async result back to C++ and QML. // External globals for transporting of async result back to C++ and QML.
QString selectedFilePath; QList<QUrl> selectedFileUrls; // Url list of selected files
bool isControllerOpen; bool isControllerOpen; // holds information if DocumentPickerController is active.
@interface DocumentPickerController () <UIDocumentPickerDelegate> @interface DocumentPickerController () <UIDocumentPickerDelegate>
...@@ -39,21 +40,45 @@ bool isControllerOpen; ...@@ -39,21 +40,45 @@ bool isControllerOpen;
[super viewDidLoad]; [super viewDidLoad];
} }
- (void)openExportDocumentPicker:(NSArray<NSURL *> *)exportUrls {
//NSLog(@"EXPORT FILE URLs: %@", exportUrls);
UIDocumentPickerViewController *documentPicker = [[UIDocumentPickerViewController alloc] initWithURLs:exportUrls inMode:UIDocumentPickerModeExportToService];
documentPicker.delegate = self;
documentPicker.modalPresentationStyle = UIModalPresentationFormSheet;
[self presentViewController:documentPicker animated:YES completion:nil];
}
- (void)openImportDocumentPicker { - (void)openImportDocumentPicker {
UIDocumentPickerViewController *documentPicker = [[UIDocumentPickerViewController alloc] initWithDocumentTypes:@[@"public.data"] inMode:UIDocumentPickerModeImport]; UIDocumentPickerViewController *documentPicker = [[UIDocumentPickerViewController alloc] initWithDocumentTypes:@[@"public.data"] inMode:UIDocumentPickerModeImport];
documentPicker.delegate = self; documentPicker.delegate = self;
// Next property does not work with iOS < 11. // Next property does not work with iOS < 11.
// Apple bug: Selected files are not picked if multiple select is on. // Apple bug: Selected files are not picked if multiple select is on.
//documentPicker.allowsMultipleSelection = YES; documentPicker.allowsMultipleSelection = YES;
documentPicker.modalPresentationStyle = UIModalPresentationFormSheet; documentPicker.modalPresentationStyle = UIModalPresentationFormSheet;
[self presentViewController:documentPicker animated:YES completion:nil]; [self presentViewController:documentPicker animated:YES completion:nil];
} }
- (void)documentPicker:(UIDocumentPickerViewController *)controller didPickDocumentAtURL:(NSURL *)url { - (void)documentPicker:(UIDocumentPickerViewController *)controller didPickDocumentsAtURLs:(NSArray<NSURL *> *)urls {
if (controller.documentPickerMode == UIDocumentPickerModeImport) { if (controller.documentPickerMode == UIDocumentPickerModeImport) {
selectedFilePath = QString::fromNSString(url.absoluteString);
isControllerOpen = false; NSLog(@"SELECTED FILE URLs: %@", urls);
QList<QUrl> qurls;
for (NSURL *url in urls) {
QUrl tmpUrl = QUrl::fromNSURL(url);
qurls.append(tmpUrl);
}
selectedFileUrls = qurls;
} else if (controller.documentPickerMode == UIDocumentPickerModeExportToService) {
NSLog(@"STORAGE FILE URLs: %@", urls);
} }
isControllerOpen = false;
} }
- (void)documentPickerWasCancelled:(UIDocumentPickerViewController *)controller { - (void)documentPickerWasCancelled:(UIDocumentPickerViewController *)controller {
......
/* /*
* Copyright (C) 2014-2018 CZ.NIC * Copyright (C) 2014-2019 CZ.NIC
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include <QObject> #include <QObject>
#include <QString> #include <QString>
#include <QStringList> #include <QStringList>
#include <QUrl>
/*! /*!
* @brief Provides objective-C IO methods for interaction with iCLoud. * @brief Provides objective-C IO methods for interaction with iCLoud.
...@@ -113,18 +114,19 @@ public: ...@@ -113,18 +114,19 @@ public:
/*! /*!
* @brief Create and open document picker controller. * @brief Create and open document picker controller.
* *
* @param[in] exportFilesPath File paths for export (can be empty).
* @return True if document picker controller is created and opened. * @return True if document picker controller is created and opened.
*/ */
static static
bool openDocumentPickerController(void); bool openDocumentPickerController(const QStringList &exportFilesPath);
/*! /*!
* @brief Move file from app temporary inbox to local app sandbox. * @brief Move file from app temporary inbox to local app sandbox.
* *
* @param[in] oldFilePath Source file path from inbox. * @param[in] sourceFileUrl Source file url from inbox.
* @param[in] newFilePath Target path to local app sandbox. * @param[in] newFilePath Target path to local app sandbox.
* @return Full path where file was moved. * @return Full path where file was moved.
*/ */
static static
QString moveFile(const QString &oldFilePath, const QString &newFilePath); QUrl moveFile(const QUrl &sourceFileUrl, const QString &newFilePath);
}; };
/* /*
* Copyright (C) 2014-2018 CZ.NIC * Copyright (C) 2014-2019 CZ.NIC
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
...@@ -221,7 +221,7 @@ bool ICloudIo::isDownloadedFromCloud(const QString &cloudFilePath) ...@@ -221,7 +221,7 @@ bool ICloudIo::isDownloadedFromCloud(const QString &cloudFilePath)
return false; return false;
} }
bool ICloudIo::openDocumentPickerController(void) bool ICloudIo::openDocumentPickerController(const QStringList &exportFilesPath)
{ {
static DocumentPickerController* dpc = nil; static DocumentPickerController* dpc = nil;
if (dpc != nil) { if (dpc != nil) {
...@@ -234,18 +234,38 @@ bool ICloudIo::openDocumentPickerController(void) ...@@ -234,18 +234,38 @@ bool ICloudIo::openDocumentPickerController(void)
if (rootv != nil) { if (rootv != nil) {
dpc = [[DocumentPickerController alloc] init]; dpc = [[DocumentPickerController alloc] init];
[rootv addChildViewController:dpc]; [rootv addChildViewController:dpc];
if (exportFilesPath.isEmpty()) {
// exportFilesPath is empty so import Document Picker will open
[dpc openImportDocumentPicker]; [dpc openImportDocumentPicker];
} else {
// exportFilesPath is not empty so export Document Picker will open
NSMutableArray<NSURL*> *exportUrls = [NSMutableArray array];
// covert export file paths to array of nsurl
for (int i = 0; i < exportFilesPath.count(); ++i) {
QUrl url = QUrl::fromLocalFile(exportFilesPath.at(i));
if (url.isValid()) {
NSURL *fileUrl = url.toNSURL();
[exportUrls addObject:fileUrl];
//NSLog(@"ADD FILE URL to list: %@", fileUrl);
} else {
NSLog(@"ERROR FILE URL: %@", url.toNSURL());
}
}
if ([exportUrls count] > 0) {
[dpc openExportDocumentPicker:exportUrls];
}
}
return true; return true;
} }
return false; return false;
} }
QString ICloudIo::moveFile(const QString &oldFilePath, QUrl ICloudIo::moveFile(const QUrl &sourceFileUrl,
const QString &newFilePath) const QString &newFilePath)
{ {
// Convert string path to URL // Convert string path to URL
NSURL *ofp = [NSURL URLWithString:oldFilePath.toNSString()]; NSURL *ofp = sourceFileUrl.toNSURL();
NSURL *np = [NSURL fileURLWithPath:newFilePath.toNSString()]; NSURL *np = [NSURL fileURLWithPath:newFilePath.toNSString()];
NSString *fileName = [ofp lastPathComponent]; NSString *fileName = [ofp lastPathComponent];
...@@ -254,7 +274,7 @@ QString ICloudIo::moveFile(const QString &oldFilePath, ...@@ -254,7 +274,7 @@ QString ICloudIo::moveFile(const QString &oldFilePath,
if (![[NSFileManager defaultManager] createDirectoryAtURL:np if (![[NSFileManager defaultManager] createDirectoryAtURL:np
withIntermediateDirectories:YES attributes:nil error:&error]) { withIntermediateDirectories:YES attributes:nil error:&error]) {
NSLog(@"Local storage: Create message subdirectories error: %@", error); NSLog(@"Local storage: Create message subdirectories error: %@", error);
return QString(); return QUrl();
} }
NSURL *nfp = [np URLByAppendingPathComponent:fileName]; NSURL *nfp = [np URLByAppendingPathComponent:fileName];
...@@ -267,13 +287,13 @@ QString ICloudIo::moveFile(const QString &oldFilePath, ...@@ -267,13 +287,13 @@ QString ICloudIo::moveFile(const QString &oldFilePath,
if ([[NSFileManager defaultManager] moveItemAtURL:ofp toURL:nfp error:&error]) { if ([[NSFileManager defaultManager] moveItemAtURL:ofp toURL:nfp error:&error]) {
NSLog(@"Local storage: File has moved to target path."); NSLog(@"Local storage: File has moved to target path.");
return QString::fromNSString(nfp.absoluteString); return QUrl::fromNSURL(nfp);
} else { } else {
if (error.code == NSFileWriteFileExistsError) { if (error.code == NSFileWriteFileExistsError) {
NSLog(@"Local storage: File with the same name already exists in the target path."); NSLog(@"Local storage: File with the same name already exists in the target path.");
} else { } else {
NSLog(@"Local storage: Error code: %zd %@", error.code, error); NSLog(@"Local storage: Error code: %zd %@", error.code, error);
} }
return QString(); return QUrl();
} }
} }
/* /*
* Copyright (C) 2014-2018 CZ.NIC * Copyright (C) 2014-2019 CZ.NIC
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
...@@ -21,11 +21,9 @@ ...@@ -21,11 +21,9 @@
* the two. * the two.
*/ */
#include <QDebug>
#include <QDir> #include <QDir>
#include <QFileInfo> #include <QFileInfo>
#include <QMessageBox> #include <QMessageBox>
#include <QUrl>
#include "src/auxiliaries/icloud_helper.h" #include "src/auxiliaries/icloud_helper.h"
#include "src/io/filesystem.h" #include "src/io/filesystem.h"
...@@ -51,12 +49,6 @@ ICloudHelper::ICloudHelper(QObject *parent) ...@@ -51,12 +49,6 @@ ICloudHelper::ICloudHelper(QObject *parent)
{ {
} }
/* TODO - removed this tmp function if all will done. */
QStringList testCloudPathList(void)
{
return QStringList() << "file:///private/var/mobile/Library/Mobile%20Documents/iCloud~cz~nic~mobile-datovka/Documents/Send/" << "file:///private/var/mobile/Library/Mobile%20Documents/iCloud~cz~nic~mobile-datovka/Documents/pokus/" << "file:///private/var/mobile/Library/Mobile%20Documents/iCloud~cz~nic~mobile-datovka/Documents/Send/app_delegate.mm" << "file:///private/var/mobile/Library/Mobile%20Documents/iCloud~cz~nic~mobile-datovka/Documents/wh5ef3/6765996/priloha.txt" << "file:///private/var/mobile/Library/Mobile%20Documents/iCloud~cz~nic~mobile-datovka/Documents/wh5ef3/" << "file:///private/var/mobile/Library/Mobile%20Documents/iCloud~cz~nic~mobile-datovka/Documents/wh5ef3/6766050/" << "file:///private/var/mobile/Library/Mobile%20Documents/iCloud~cz~nic~mobile-datovka/Documents/wh5ef3/6765996/" << "file:///private/var/mobile/Library/Mobile%20Documents/iCloud~cz~nic~mobile-datovka/Documents/pokus/dmg_background.png" << "file:///private/var/mobile/Library/Mobile%20Documents/iCloud~cz~nic~mobile-datovka/Documents/pokus/datovka.svg" << "file:///private/var/mobile/Library/Mobile%20Documents/iCloud~cz~nic~mobile-datovka/Documents/4i2xd7/623345688/DZ_623345688.zfo" << "file:///private/var/mobile/Library/Mobile%20Documents/iCloud~cz~nic~mobile-datovka/Documents/Send/datovka.png" << "file:///private/var/mobile/Library/Mobile%20Documents/iCloud~cz~nic~mobile-datovka/Documents/wh5ef3/6766050/dokument.odt" << "file:///private/var/mobile/Library/Mobile%20Documents/iCloud~cz~nic~mobile-datovka/Documents/4i2xd7/623345688/5000FC241550444E8BE9C217BF5247EA.pdf" << "file:///private/var/mobile/Library/Mobile%20Documents/iCloud~cz~nic~mobile-datovka/Documents/wh5ef3/6766050/notification.mp3" << "file:///private/var/mobile/Library/Mobile%20Documents/iCloud~cz~nic~mobile-datovka/Documents/wh5ef3/6766050/dokument.pdf" << "file:///private/var/mobile/Library/Mobile%20Documents/iCloud~cz~nic~mobile-datovka/Documents/wh5ef3/6766050/obrazek.png" << "file:///private/var/mobile/Library/Mobile%20Documents/iCloud~cz~nic~mobile-datovka/Documents/4i2xd7/" << "file:///private/var/mobile/Library/Mobile%20Documents/iCloud~cz~nic~mobile-datovka/Documents/4i2xd7/623345688/";
}
void ICloudHelper::createCloudConteiner(void) void ICloudHelper::createCloudConteiner(void)
{ {
debugFuncCall(); debugFuncCall();
...@@ -304,6 +296,11 @@ void ICloudHelper::clearSendDir(void) ...@@ -304,6 +296,11 @@ void ICloudHelper::clearSendDir(void)
QDir dir(appSendDirPath()); QDir dir(appSendDirPath());
dir.removeRecursively(); dir.removeRecursively();
/*
// TODO - used for experiments and testing only
QDir dir2(dfltAttachSavingLoc());
dir2.removeRecursively();
*/
} }
void ICloudHelper::receivedCloudHierarchy(void) void ICloudHelper::receivedCloudHierarchy(void)
...@@ -332,8 +329,8 @@ void ICloudHelper::openDocumentPickerController(void) ...@@ -332,8 +329,8 @@ void ICloudHelper::openDocumentPickerController(void)
return; return;
} }
selectedFilePath.clear(); selectedFileUrls.clear();
isControllerOpen = ICloudIo::openDocumentPickerController(); isControllerOpen = ICloudIo::openDocumentPickerController(QStringList());
if (isControllerOpen) { if (isControllerOpen) {
connect(m_dpcTimer, SIGNAL(timeout()), connect(m_dpcTimer, SIGNAL(timeout()),
this, SLOT(receivedSelectedFilePath())); this, SLOT(receivedSelectedFilePath()));
...@@ -345,34 +342,57 @@ void ICloudHelper::openDocumentPickerController(void) ...@@ -345,34 +342,57 @@ void ICloudHelper::openDocumentPickerController(void)
void ICloudHelper::receivedSelectedFilePath(void) void ICloudHelper::receivedSelectedFilePath(void)
{ {
#ifdef Q_OS_IOS #ifdef Q_OS_IOS
if (!isControllerOpen) { if (!isControllerOpen) {
m_dpcTimer->stop(); m_dpcTimer->stop();
disconnect(m_dpcTimer, SIGNAL(timeout()), disconnect(m_dpcTimer, SIGNAL(timeout()),
this, SLOT(receivedSelectedFilePath())); this, SLOT(receivedSelectedFilePath()));
if (!selectedFilePath.isEmpty()) {
moveFileToSendDir(selectedFilePath); if (!selectedFileUrls.isEmpty()) {
selectedFilePath.clear(); foreach (const QUrl &fileUrl, selectedFileUrls) {
moveFileToSendDir(fileUrl);
}
selectedFileUrls.clear();
} }
} }
#endif #endif
} }
void ICloudHelper::moveFileToSendDir(const QString &filePath) void ICloudHelper::moveFileToSendDir(const QUrl &sourceFileUrl)
{ {
#ifdef Q_OS_IOS #ifdef Q_OS_IOS
if (filePath.isEmpty()) { if (Q_UNLIKELY(!sourceFileUrl.isValid())) {
return; return;
} }
QString lfPath = ICloudIo::moveFile(filePath, appSendDirPath());
if (!lfPath.isEmpty()) { QUrl targetFileUrl = ICloudIo::moveFile(sourceFileUrl, appSendDirPath());
lfPath = QUrl::fromPercentEncoding(lfPath.toUtf8()); if (targetFileUrl.isValid()) {
lfPath = lfPath.replace("file://", ""); targetFileUrl.setScheme(QString());
emit fileSelectedSig(lfPath); emit fileSelectedSig(targetFileUrl.toString());
} }
#endif #endif
} }
void ICloudHelper::storeFilesToDeviceStorage(const QStringList &srcFilePaths)
{
debugFuncCall();
#ifdef Q_OS_IOS
if (Q_UNLIKELY(srcFilePaths.isEmpty())) {
return;
}
ICloudIo::openDocumentPickerController(srcFilePaths);
#else /* !Q_OS_IOS */
Q_UNUSED(srcFilePaths);
#endif /* Q_OS_IOS */
}
/* /*
* Copyright (C) 2014-2018 CZ.NIC * Copyright (C) 2014-2019 CZ.NIC
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <QString> #include <QString>
#include <QStringList> #include <QStringList>
#include <QTimer> #include <QTimer>
#include <QUrl>
/* /*
* External global variables. These are using for transporting of async results * External global variables. These are using for transporting of async results
...@@ -35,7 +36,7 @@ ...@@ -35,7 +36,7 @@
*/ */
extern QStringList iCloudFileList; extern QStringList iCloudFileList;
extern bool isSearchRunning; extern bool isSearchRunning;
extern QString selectedFilePath; extern QList<QUrl> selectedFileUrls;
extern bool isControllerOpen; extern bool isControllerOpen;
/*! /*!
...@@ -80,6 +81,14 @@ public: ...@@ -80,6 +81,14 @@ public:
void storeFilesToCloud(const QStringList &srcFilePaths, void storeFilesToCloud(const QStringList &srcFilePaths,
const QString &targetPath); const QString &targetPath);
/*!
* @brief Store files to device local storage.
*
* @param[in] srcFilePaths List of file paths to be saved into storage.
*/
Q_INVOKABLE
void storeFilesToDeviceStorage(const QStringList &srcFilePaths);
/*! /*!
* @brief Download file from iCloud if not exists in the local storage. * @brief Download file from iCloud if not exists in the local storage.
* *
...@@ -171,9 +180,9 @@ private: ...@@ -171,9 +180,9 @@ private:
/*! /*!
* @brief Move file from app temporary inbox to send path. * @brief Move file from app temporary inbox to send path.
* *
* @param[in] filePath Source file path from inbox. * @param[in] sourceFileUrl Source file url from inbox.
*/ */
void moveFileToSendDir(const QString &filePath); void moveFileToSendDir(const QUrl &sourceFileUrl);
/* Detect moment when async search response with iCloud hierarchy finished. */ /* Detect moment when async search response with iCloud hierarchy finished. */
QTimer *m_icloudTimer; QTimer *m_icloudTimer;
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <QDesktopServices> #include <QDesktopServices>
#include <QDir> #include <QDir>
#include <QFileInfo> #include <QFileInfo>
#include <QMessageBox>
#include <QQmlEngine> #include <QQmlEngine>
#include <QStringBuilder> #include <QStringBuilder>
...@@ -639,6 +640,27 @@ void Files::sendAttachmentEmailZfo(const QVariant &attachModelVariant, ...@@ -639,6 +640,27 @@ void Files::sendAttachmentEmailZfo(const QVariant &attachModelVariant,
QString::number(msgId)); QString::number(msgId));
} }
#ifdef Q_OS_IOS
static
void exportFilesiOS(const QStringList &destFilePaths,
const QString &targetDir)
{
QMessageBox msgBox;
msgBox.setText(QObject::tr("You can export files into iCloud or into device local storage."));
msgBox.setDetailedText(QObject::tr("Do you want to export files to Datovka iCloud container?"));
msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);
msgBox.setDefaultButton(QMessageBox::No);
int ret = msgBox.exec();
if (ret == QMessageBox::Yes) {
ICloudHelper::storeFilesToCloud(destFilePaths, targetDir);
} else if (ret == QMessageBox::No) {
ICloudHelper ich;
ich.storeFilesToDeviceStorage(destFilePaths);
}
}
#endif
void Files::saveMsgFilesToDisk(const QString &userName, void Files::saveMsgFilesToDisk(const QString &userName,
const QString &msgIdStr, MsgAttachFlags attachFlags) const QString &msgIdStr, MsgAttachFlags attachFlags)
{ {
...@@ -723,8 +745,7 @@ void Files::saveMsgFilesToDisk(const QString &userName, ...@@ -723,8 +745,7 @@ void Files::saveMsgFilesToDisk(const QString &userName,
#else #else
ICloudHelper::storeFilesToCloud(destFilePaths, joinDirs(userName, exportFilesiOS(destFilePaths, joinDirs(userName, msgIdStr));
msgIdStr));
#endif #endif
} }
...@@ -763,7 +784,7 @@ void Files::saveAttachmentsToDiskZfo(const QVariant &attachModelVariant, ...@@ -763,7 +784,7 @@ void Files::saveAttachmentsToDiskZfo(const QVariant &attachModelVariant,
#else #else
ICloudHelper::storeFilesToCloud(destFilePaths, msgIdStr); exportFilesiOS(destFilePaths, msgIdStr);
#endif #endif
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment