Commit 8003c88a authored by Martin Straka's avatar Martin Straka

Added iCloud file downloading during its selection

parent eb82436d
......@@ -147,17 +147,19 @@ ICloudIo::ICloudResult ICloudIo::moveFileToCloud(
QString ICloudIo::copyFileFromCloud(const QString &cloudFilePath,
const QString &localFilePath)
{
// Test if file was downloaded from iCloud
if (!isDownloadedFromCloud(cloudFilePath)) {
NSLog(@"Local: File has not been downloaded yet from iCloud.");
return QString();
}
NSError *error = nil;
// Convert string path to URL
NSURL *fileCloudUrl = [NSURL URLWithString:cloudFilePath.toNSString()];
NSURL* localFileUrl = [NSURL fileURLWithPath:localFilePath.toNSString()];
NSString *fileName = [fileCloudUrl lastPathComponent];
// Create subdirectorues on Local
NSError *error = nil;
if (![[NSFileManager defaultManager] createDirectoryAtURL:localFileUrl
withIntermediateDirectories:YES attributes:nil error:&error]) {
NSLog(@"Local: Create message subdirectories error: %@", error.localizedDescription);
......@@ -165,23 +167,23 @@ QString ICloudIo::copyFileFromCloud(const QString &cloudFilePath,
}
NSURL *fileLocalUrl = [localFileUrl URLByAppendingPathComponent:fileName];
NSLog(@"iCloud url: %@", fileCloudUrl);
NSLog(@"Local file url: %@", fileLocalUrl);
//NSLog(@"iCloud url: %@", fileCloudUrl);
//NSLog(@"Local file url: %@", fileLocalUrl);
// Remove file from local
[[NSFileManager defaultManager] removeItemAtURL:fileLocalUrl error:&error];
if ([[NSFileManager defaultManager] copyItemAtURL:fileCloudUrl toURL:fileLocalUrl error:&error]) {
NSLog(@"Local: File has been uploaded.");
return QString();
NSLog(@"Local: File has copied to app sandbox.");
return QString::fromNSString(fileLocalUrl.absoluteString);
} else {
if (error.code == NSFileWriteFileExistsError) {
NSLog(@"Local: File with the same name already exists.");
return QString();
} else if (error.code == NSFileReadNoSuchFileError) {
NSLog(@"Local: File has not been downloaded yet from iCloud.");
return QString();
NSLog(@"Local: File has not downloaded yet from iCloud.");
} else {
NSLog(@"Local: Error code: %zd %@", error.code, error.localizedDescription);
NSLog(@"Local: Error code: %zd %@", error.code, error);
}
}
return QString();
......@@ -197,18 +199,22 @@ bool ICloudIo::isDownloadedFromCloud(const QString &cloudFilePath)
NSError *error = nil;
NSString *downloadStatus = nil;
NSURL *fileCloudUrl = [NSURL URLWithString:cloudFilePath.toNSString()];
if ([fileCloudUrl getResourceValue:&downloadStatus forKey:NSURLUbiquitousItemDownloadingStatusKey error:&error] == YES) {
if ([downloadStatus isEqualToString:NSURLUbiquitousItemDownloadingStatusNotDownloaded] == YES) {
NSLog(@"File must be downloaded: %@", fileCloudUrl);
NSLog(@"File missing and must be downloaded: %@", fileCloudUrl);
[[NSFileManager defaultManager] startDownloadingUbiquitousItemAtURL:fileCloudUrl error:&error];
return false;
} else if ([downloadStatus isEqualToString:NSURLUbiquitousItemDownloadingStatusDownloaded] == YES) {
NSLog(@"Up-to-date version of file must be downloaded: %@", fileCloudUrl);
[[NSFileManager defaultManager] startDownloadingUbiquitousItemAtURL:fileCloudUrl error:&error];
return false;
} else {
NSLog(@"File has been downloaded: %@", fileCloudUrl);
NSLog(@"Up-to-date version of file is available: %@", fileCloudUrl);
return true;
}
}
return true;
return false;
}
......@@ -62,6 +62,7 @@ Dialog {
property int selectedFileIndex: -1
property bool showDirs: true
property bool showFiles: true
property bool iOS: false
signal finished(variant pathListModel)
......@@ -69,7 +70,8 @@ Dialog {
return (root.showDirs && !root.showFiles);
}
function raise(title, filters, showFiles, targetLocation) {
function raise(title, filters, showFiles, targetLocation, isiOS) {
iOS = isiOS
if (targetLocation !== "") {
folderNavigation.visible = false
folderModel.folder = "file://" + targetLocation
......@@ -80,6 +82,9 @@ Dialog {
if (filters !== "") {
folderModel.nameFilters = filters
}
if (iOS) {
folderModel.folder = standardLocationUrl(InteractionFilesystem.DOCUMENTS_LOCATION)
}
selectedFileIndex = -1
// clear add path list model
pathListModel.clear()
......@@ -128,6 +133,7 @@ Dialog {
ColumnLayout {
id: folderNavigation
AccessibleComboBox {
visible: !iOS
anchors {
left: parent.left;
right: parent.right;
......@@ -207,7 +213,7 @@ Dialog {
showFiles: root.showFiles
showDirsFirst: true
nameFilters: ["*.*"]
folder: standardLocationUrl(InteractionFilesystem.DESKTOP_LOCATION)
folder: standardLocationUrl(InteractionFilesystem.DOCUMENTS_LOCATION)
onFolderChanged: {
selectedFileIndex = -1
pathField.text = stripUrlPrefix(folder)
......
......@@ -88,15 +88,19 @@ Dialog {
target: iCloudHelper
onCloudContentSig: {
iCloudHelper.setCloudFileModel(cloudFileListModel, iCloudFileList);
if (cloudFileListModel.rowCount() > 1) {
if (cloudFileListModel.rowCount() > 0) {
cloudFileList.visible = true
emptyList.visible = false
emptyList.visible = !cloudFileList.visible
} else {
emptyList.text = qsTr("No files in the iCloud.")
cloudFileList.visible = false
emptyList.visible = !cloudFileList.visible
}
}
onCloudActivitySig: {
emptyList.text = txt
cloudFileList.visible = false
emptyList.visible = true
emptyList.visible = !cloudFileList.visible
}
}
Component {
......@@ -128,7 +132,7 @@ Dialog {
font.bold: true
}
Text {
text: rFileShortPath
text: "iCloud:" + rFileShortPath
color: datovkaPalette.mid
font.pointSize: textFontSizeSmall
}
......@@ -143,7 +147,10 @@ Dialog {
MouseArea {
anchors.fill: parent
onClicked: {
cloudFileListModel.setFileSelected(rFileCloudPath, !rFileSelected)
if (!rFileSelected) {
iCloudHelper.downloadFileFromCloud(rFileCloudPath)
}
cloudFileListModel.setFileSelected(rFileCloudPath)
}
}
} // Rectangle
......@@ -198,7 +205,10 @@ Dialog {
onAccepted: {
for (var i = 0; i < cloudFileListModel.rowCount(); ++i) {
if (cloudFileListModel.fileSelected(i)) {
pathListModel.append({path: cloudFileListModel.fileCloudPathFromRow(i)})
var filePath = iCloudHelper.copyFileFromCloud(cloudFileListModel.fileCloudPathFromRow(i), cloudFileListModel.fileShortCloudPathFromRow(i))
if (filePath !== "") {
pathListModel.append({path: filePath})
}
}
}
finished(pathListModel)
......
......@@ -54,6 +54,8 @@ Item {
property string text_COLOR_RED: "#ff0000"
property bool iOS: false
/* This property holds total attachment size in bytes */
property int totalAttachmentSizeBytes: 0
......@@ -163,7 +165,30 @@ Item {
}
}
/* Append selected files to send model */
function appendFilesToSendModel(pathListModel) {
var listLength = pathListModel.count
for (var j = 0; j < listLength; ++j) {
var isInFiletList = false
for (var i = 0; i < sendMsgAttachmentModel.rowCount(); i++) {
if (sendMsgAttachmentModel.filePathFromRow(i) === pathListModel.get(j).path) {
isInFiletList = true
break
}
}
if (!isInFiletList) {
var fileName = getFileNameFromPath(pathListModel.get(j).path)
var fileSizeBytes = files.getAttachmentSizeInBytes(pathListModel.get(j).path)
sendMsgAttachmentModel.appendFileFromPath(FileIdType.NO_FILE_ID,
fileName, pathListModel.get(j).path, fileSizeBytes)
totalAttachmentSizeBytes = sendMsgAttachmentModel.dataSizeSum()
}
}
pathListModel.clear()
}
Component.onCompleted: {
iOS = files.isIos()
actionButton.enabled = false
initPDZ.visible = false
initPDZ.checked = false
......@@ -194,52 +219,13 @@ Item {
FileDialogue {
id: fileDialogue
multiSelect: true
onFinished: {
var listLength = pathListModel.count
for (var j = 0; j < listLength; ++j) {
var isInFiletList = false
for (var i = 0; i < sendMsgAttachmentModel.rowCount(); i++) {
if (sendMsgAttachmentModel.filePathFromRow(i) === pathListModel.get(j).path) {
isInFiletList = true
break
}
}
if (!isInFiletList) {
var fileName = getFileNameFromPath(pathListModel.get(j).path)
var fileSizeBytes = files.getAttachmentSizeInBytes(pathListModel.get(j).path)
sendMsgAttachmentModel.appendFileFromPath(FileIdType.NO_FILE_ID,
fileName, pathListModel.get(j).path, fileSizeBytes)
totalAttachmentSizeBytes = sendMsgAttachmentModel.dataSizeSum()
}
}
pathListModel.clear()
}
onFinished: appendFilesToSendModel(pathListModel)
}
/* File dialog for choose of files from iCloud */
FileDialogueIos {
id: fileDialogueIos
onFinished: {
var listLength = pathListModel.count
for (var j = 0; j < listLength; ++j) {
var localFilePath = iCloudHelper.downloadFileFromCloud(pathListModel.get(j).path)
var isInFiletList = false
for (var i = 0; i < sendMsgAttachmentModel.rowCount(); i++) {
if (sendMsgAttachmentModel.filePathFromRow(i) === localFilePath) {
isInFiletList = true
break
}
}
if (!isInFiletList) {
var fileName = getFileNameFromPath(localFilePath)
var fileSizeBytes = files.getAttachmentSizeInBytes(localFilePath)
sendMsgAttachmentModel.appendFileFromPath(FileIdType.NO_FILE_ID,
fileName, localFilePath, fileSizeBytes)
totalAttachmentSizeBytes = sendMsgAttachmentModel.dataSizeSum()
}
}
pathListModel.clear()
}
onFinished: appendFilesToSendModel(pathListModel)
}
/* Holds send message recipent list model */
......@@ -524,12 +510,12 @@ Item {
font.pointSize: defaultTextFont.font.pointSize
text: qsTr("Add file")
onClicked: {
fileDialogue.raise(qsTr("Select files"), ["*.*"], true, "")
fileDialogue.raise(qsTr("Select files"), ["*.*"], true, "", iOS)
}
}
AccessibleButton {
id: icloud
visible: files.isIos()
visible: iOS
height: inputItemHeight
font.pointSize: defaultTextFont.font.pointSize
text: qsTr("iCloud")
......
......@@ -21,9 +21,11 @@
* the two.
*/
#include <QDebug>
#include <QDir>
#include <QFileInfo>
#include <QMessageBox>
#include <QUrl>
#include "src/auxiliaries/icloud_helper.h"
#include "src/io/filesystem.h"
......@@ -33,6 +35,7 @@
#ifdef Q_OS_IOS
#include "ios/src/icloud_io.h"
#define ICLOUD_DATOVKA_CONTAINER_NAME "Datovka"
#define ICLOUD_FILE_CONTAINER_ID "iCloud~cz~nic~mobile-datovka/Documents"
#endif /* Q_OS_IOS */
#ifndef Q_OS_IOS
......@@ -54,7 +57,7 @@ QStringList testCloudPathList(void)
void ICloudHelper::createCloudConteiner(void)
{
debugSlotCall();
debugFuncCall();
#ifdef Q_OS_IOS
......@@ -65,7 +68,7 @@ void ICloudHelper::createCloudConteiner(void)
void ICloudHelper::getCloudHierarchyAsync(void)
{
debugSlotCall();
debugFuncCall();
#ifdef Q_OS_IOS
......@@ -94,7 +97,7 @@ void ICloudHelper::getCloudHierarchyAsync(void)
void ICloudHelper::storeFilesToCloud(const QStringList &srcFilePaths,
const QString &targetPath)
{
debugSlotCall();
debugFuncCall();
#ifdef Q_OS_IOS
......@@ -152,14 +155,12 @@ finish:
/* Show final notification */
if (success) {
qCritical() << "Files have been saved to iCloud.";
QMessageBox::critical(Q_NULLPTR, tr("iCloud saving"),
tr("Files have been saved to iCloud.") + "\n\n" +
tr("Path: '%1'").arg(QString(ICLOUD_DATOVKA_CONTAINER_NAME)
+ "/" + targetPath),
QMessageBox::Ok);
} else {
qCritical() << "Files upload to iCloud failed!";
QString txt;
foreach (const QString &error, errorUploads) {
txt += "\n" + error;
......@@ -178,22 +179,58 @@ finish:
#endif /* Q_OS_IOS */
}
QString ICloudHelper::downloadFileFromCloud(const QString &cloudFilePath)
bool ICloudHelper::downloadFileFromCloud(const QString &cloudFilePath)
{
debugSlotCall();
debugFuncCall();
#ifdef Q_OS_IOS
QString localFilePath;
QFileInfo fi(cloudFilePath);
localFilePath = appSendDirPath() + QDir::separator() +
QUrl::fromPercentEncoding(fi.fileName().toUtf8());
return ICloudIo::isDownloadedFromCloud(cloudFilePath);
#else
Q_UNUSED(cloudFilePath);
return false;
#endif
}
QString ICloudHelper::copyFileFromCloud(const QString &cloudFilePath,
const QString &localFilePath)
{
debugFuncCall();
#ifdef Q_OS_IOS
ICloudIo::copyFileFromCloud(cloudFilePath, appSendDirPath());
return localFilePath;
QString lfPath = ICloudIo::copyFileFromCloud(cloudFilePath,
appSendDirPath() + localFilePath);
if (!lfPath.isEmpty()) {
lfPath = QUrl::fromPercentEncoding(lfPath.toUtf8());
lfPath = lfPath.replace("file://", "");
return lfPath;
} else {
return QString();
}
#else
Q_UNUSED(cloudFilePath);
Q_UNUSED(localFilePath);
return QString();
#endif
}
/*
* Retrun short iCloud path.
*/
QString getShortPathFromCloudPath(const QString &fileCloudPath)
{
#ifdef Q_OS_IOS
// Get short file path from iCloud path
QString pattern(ICLOUD_FILE_CONTAINER_ID);
int pos = fileCloudPath.indexOf(pattern) + pattern.length();
return fileCloudPath.mid(pos);
#else
Q_UNUSED(fileCloudPath);
return QString();
#endif
}
......@@ -201,9 +238,9 @@ QString ICloudHelper::downloadFileFromCloud(const QString &cloudFilePath)
void ICloudHelper::setCloudFileModel(const QVariant &cloudFileModelVariant,
const QStringList &fileList)
{
debugSlotCall();
debugFuncCall();
/* Obtain pointer to attachment model. */
/* Obtain pointer to icloud file model from variant. */
CloudFileListModel *cloudModel =
CloudFileListModel::fromVariant(cloudFileModelVariant);
if (cloudModel == Q_NULLPTR) {
......@@ -211,16 +248,18 @@ void ICloudHelper::setCloudFileModel(const QVariant &cloudFileModelVariant,
return;
}
foreach (const QString &file, fileList) {
QFileInfo fi(file);
foreach (const QString &fileCloudPath, fileList) {
QFileInfo fi(fileCloudPath);
if (fi.fileName().isEmpty()) {
// Skip directories
continue;
}
QString filePath = fi.path();
QString pattern("iCloud~cz~nic~mobile-datovka/Documents");
int pos = filePath.indexOf(pattern) + pattern.length();
filePath = QStringLiteral("iCloud:Datovka") + filePath.mid(pos) + QStringLiteral("/");
cloudModel->appendFileFromCloud(file, fi.fileName(), filePath, false);
// Append file to model, false means file is unselected
cloudModel->appendFileFromCloud(fileCloudPath,
QUrl::fromPercentEncoding(fi.fileName().toUtf8()),
getShortPathFromCloudPath(fi.path()), false);
}
}
......@@ -242,9 +281,7 @@ void ICloudHelper::receivedCloudHierarchy(void)
m_timer->stop();
disconnect(m_timer, SIGNAL(timeout()),
this, SLOT(receivedCloudHierarchy()));
if (!iCloudFileList.isEmpty()) {
emit cloudContentSig(iCloudFileList);
}
emit cloudContentSig(iCloudFileList);
} else {
emit cloudActivitySig(tr("Searching for iCloud files..."));
}
......
......@@ -72,10 +72,21 @@ public:
* @brief Download file from iCloud if not exists in the local storage.
*
* @param[in] cloudFilePath File path in iCloud.
* @return Full path where file will stored.
* @return True if success.
*/
Q_INVOKABLE
QString downloadFileFromCloud(const QString &cloudFilePath);
bool downloadFileFromCloud(const QString &cloudFilePath);
/*!
* @brief Copy single file from iCloud continer to Datovka sandbox.
*
* @param[in] cloudFilePath Source file path.
* @param[in] localFilePath iCloud target path.
* @return Full path to app sandbox where file was stored.
*/
Q_INVOKABLE
QString copyFileFromCloud(const QString &cloudFilePath,
const QString &localFilePath);
/*!
* @brief Set iCloud file model in QML.
......
......@@ -167,6 +167,15 @@ QString CloudFileListModel::fileCloudPathFromRow(int row)
return m_files[row].fileClaudPath();
}
QString CloudFileListModel::fileShortCloudPathFromRow(int row)
{
if ((row < 0) || (row >= m_files.size())) {
return QString();
}
return m_files[row].fileShortPath();
}
Qt::ItemFlags CloudFileListModel::flags(const QModelIndex &index) const
{
return QAbstractListModel::flags(index);
......@@ -181,7 +190,7 @@ void CloudFileListModel::appendFileFromCloud(const QString &fileClaudPath,
endInsertRows();
}
void CloudFileListModel::setFileSelected(const QString &filePath, bool selected)
void CloudFileListModel::setFileSelected(const QString &filePath)
{
if (Q_UNLIKELY(filePath.isEmpty())) {
return;
......@@ -190,7 +199,7 @@ void CloudFileListModel::setFileSelected(const QString &filePath, bool selected)
for (int i = 0; i < m_files.size(); ++i) {
if (filePath == m_files.at(i).fileClaudPath()) {
beginResetModel();
m_files[i].setSelected(selected);
m_files[i].setSelected(!m_files[i].selected());
endResetModel();
}
}
......
......@@ -129,6 +129,15 @@ public:
Q_INVOKABLE
QString fileCloudPathFromRow(int row);
/*!
* @brief Return file path from attachment model.
*
* @param[in] row Row specifying the item.
* @return File path string.
*/
Q_INVOKABLE
QString fileShortCloudPathFromRow(int row);
/*!
* @brief Returns item flags for given index.
*
......@@ -160,7 +169,7 @@ public:
* @brief Set file selection to the model.
*/
Q_INVOKABLE
void setFileSelected(const QString &filePath, bool selected);
void setFileSelected(const QString &filePath);
/*!
* @brief Get file selection from the model.
......
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