From 7672cb79036a2e1c22e1d6a07546ac92d34638b3 Mon Sep 17 00:00:00 2001 From: alex-z Date: Wed, 28 Sep 2022 14:26:57 +0300 Subject: Improve 'Handle local file editing' feature. Add loading popup. Add force sync before opening a file.' Signed-off-by: alex-z --- src/gui/folderman.cpp | 37 ++++++++++-- src/gui/folderman.h | 2 + src/gui/iconutils.cpp | 6 +- src/gui/systray.cpp | 28 +++++++++ src/gui/systray.h | 4 ++ src/gui/tray/EditFileLocallyLoadingDialog.qml | 81 +++++++++++++++++++++++++++ src/gui/tray/NCBusyIndicator.qml | 7 ++- 7 files changed, 157 insertions(+), 8 deletions(-) create mode 100644 src/gui/tray/EditFileLocallyLoadingDialog.qml (limited to 'src') diff --git a/src/gui/folderman.cpp b/src/gui/folderman.cpp index 97d4514d2..220313891 100644 --- a/src/gui/folderman.cpp +++ b/src/gui/folderman.cpp @@ -1473,11 +1473,38 @@ void FolderMan::editFileLocally(const QString &accountDisplayName, const QString return; } - // In case the VFS mode is enabled and a file is not yet hydrated, we must call QDesktopServices::openUrl from a separate thread, or, there will be a freeze. - // To avoid searching for a specific folder and checking if the VFS is enabled - we just always call it from a separate thread. - QtConcurrent::run([foundFiles] { - QDesktopServices::openUrl(QUrl::fromLocalFile(foundFiles.first())); - }); + const auto localFilePath = foundFiles.first(); + const auto folderForFile = folderForPath(localFilePath); + + if (!folderForFile) { + showError(accountFound, tr("Could not find a folder to sync."), relPath); + return; + } + + const auto relPathSplit = relPath.split(QLatin1Char('/')); + if (relPathSplit.size() > 0) { + Systray::instance()->createEditFileLocallyLoadingDialog(relPathSplit.last()); + } else { + showError(accountFound, tr("Could not find a file for local editing. Make sure its path is valid and it is synced locally."), relPath); + return; + } + folderForFile->startSync(); + _localFileEditingSyncFinishedConnections.insert(localFilePath, QObject::connect(folderForFile, &Folder::syncFinished, this, + [this, localFilePath](const OCC::SyncResult &result) { + Q_UNUSED(result); + const auto foundConnectionIt = _localFileEditingSyncFinishedConnections.find(localFilePath); + if (foundConnectionIt != std::end(_localFileEditingSyncFinishedConnections) && foundConnectionIt.value()) { + QObject::disconnect(foundConnectionIt.value()); + _localFileEditingSyncFinishedConnections.erase(foundConnectionIt); + } + // In case the VFS mode is enabled and a file is not yet hydrated, we must call QDesktopServices::openUrl + // from a separate thread, or, there will be a freeze. To avoid searching for a specific folder and checking + // if the VFS is enabled - we just always call it from a separate thread. + QtConcurrent::run([localFilePath]() { + QDesktopServices::openUrl(QUrl::fromLocalFile(localFilePath)); + Systray::instance()->destroyEditFileLocallyLoadingDialog(); + }); + })); } void FolderMan::trayOverallStatus(const QList &folders, diff --git a/src/gui/folderman.h b/src/gui/folderman.h index 9c4e9544e..77a6b6682 100644 --- a/src/gui/folderman.h +++ b/src/gui/folderman.h @@ -375,6 +375,8 @@ private: bool _appRestartRequired = false; + QMap _localFileEditingSyncFinishedConnections; + static FolderMan *_instance; explicit FolderMan(QObject *parent = nullptr); friend class OCC::Application; diff --git a/src/gui/iconutils.cpp b/src/gui/iconutils.cpp index 40ad051ce..64d3986aa 100644 --- a/src/gui/iconutils.cpp +++ b/src/gui/iconutils.cpp @@ -90,7 +90,11 @@ QImage createSvgImageWithCustomColor(const QString &fileName, const QColor &cust }(); if (iconBaseColors.contains(customColorName)) { - result = QImage{QString{OCC::Theme::themePrefix} + customColorName + QStringLiteral("/") + fileName}; + if (requestedSize.width() > 0 && requestedSize.height() > 0) { + result = QIcon(QString{OCC::Theme::themePrefix} + customColorName + QStringLiteral("/") + fileName).pixmap(requestedSize).toImage(); + } else { + result = QImage{QString{OCC::Theme::themePrefix} + customColorName + QStringLiteral("/") + fileName}; + } if (!result.isNull()) { return result; } diff --git a/src/gui/systray.cpp b/src/gui/systray.cpp index ee5200038..e52f62bc8 100644 --- a/src/gui/systray.cpp +++ b/src/gui/systray.cpp @@ -257,6 +257,34 @@ void Systray::createCallDialog(const Activity &callNotification, const AccountSt } } +void Systray::createEditFileLocallyLoadingDialog(const QString &fileName) +{ + if (_editFileLocallyLoadingDialog) { + return; + } + + qCDebug(lcSystray) << "Opening a file local editing dialog..."; + + const auto editFileLocallyLoadingDialog = new QQmlComponent(_trayEngine, QStringLiteral("qrc:/qml/src/gui/tray/EditFileLocallyLoadingDialog.qml")); + + if (editFileLocallyLoadingDialog->isError()) { + qCWarning(lcSystray) << editFileLocallyLoadingDialog->errorString(); + return; + } + + _editFileLocallyLoadingDialog = editFileLocallyLoadingDialog->createWithInitialProperties(QVariantMap{{QStringLiteral("fileName"), fileName}}); +} + +void Systray::destroyEditFileLocallyLoadingDialog() +{ + if (!_editFileLocallyLoadingDialog) { + return; + } + qCDebug(lcSystray) << "Closing a file local editing dialog..."; + _editFileLocallyLoadingDialog->deleteLater(); + _editFileLocallyLoadingDialog = nullptr; +} + void Systray::slotCurrentUserChanged() { if (_trayEngine) { diff --git a/src/gui/systray.h b/src/gui/systray.h index d8afe8066..4da1ecedf 100644 --- a/src/gui/systray.h +++ b/src/gui/systray.h @@ -88,6 +88,8 @@ public: void showUpdateMessage(const QString &title, const QString &message, const QUrl &webUrl); void setToolTip(const QString &tip); void createCallDialog(const Activity &callNotification, const AccountStatePtr accountState); + void createEditFileLocallyLoadingDialog(const QString &fileName); + void destroyEditFileLocallyLoadingDialog(); Q_REQUIRED_RESULT QString windowTitle() const; Q_REQUIRED_RESULT bool useNormalWindow() const; @@ -160,6 +162,8 @@ private: AccessManagerFactory _accessManagerFactory; QSet _callsAlreadyNotified; + + QPointer _editFileLocallyLoadingDialog; }; } // namespace OCC diff --git a/src/gui/tray/EditFileLocallyLoadingDialog.qml b/src/gui/tray/EditFileLocallyLoadingDialog.qml new file mode 100644 index 000000000..f7fbe965b --- /dev/null +++ b/src/gui/tray/EditFileLocallyLoadingDialog.qml @@ -0,0 +1,81 @@ +import QtQuick 2.15 +import QtQuick.Window 2.15 +import Style 1.0 +import com.nextcloud.desktopclient 1.0 +import QtQuick.Layouts 1.15 +import QtQuick.Controls 2.15 + +Window { + id: root + flags: Qt.Dialog | Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint + + color: "transparent" + + width: 320 + height: contentLayout.implicitHeight + + property string fileName: "" + + readonly property real fontPixelSize: Style.topLinePixelSize * 1.5 + readonly property real iconWidth: fontPixelSize * 2 + + Component.onCompleted: { + Systray.forceWindowInit(root); + x = Screen.width / 2 - width / 2 + y = Screen.height / 2 - height / 2 + root.show(); + root.raise(); + root.requestActivate(); + } + + Rectangle { + id: windowBackground + color: Style.backgroundColor + radius: Style.trayWindowRadius + border.color: Style.ncTextColor + anchors.fill: parent + } + + ColumnLayout { + id: contentLayout + anchors.left: parent.left + anchors.right: parent.right + anchors.leftMargin: Style.standardSpacing + anchors.rightMargin: Style.standardSpacing + spacing: Style.standardSpacing + NCBusyIndicator { + id: busyIndicator + Layout.topMargin: Style.standardSpacing + Layout.alignment: Qt.AlignHCenter + Layout.preferredWidth: root.iconWidth + Layout.preferredHeight: root.iconWidth + imageSourceSizeHeight: root.iconWidth + imageSourceSizeWidth: root.iconWidth + padding: 0 + color: Style.ncTextColor + running: true + } + Label { + id: labelFileName + Layout.alignment: Qt.AlignHCenter + Layout.fillWidth: true + text: root.fileName + elide: Text.ElideRight + font.bold: true + font.pixelSize: root.fontPixelSize + color: Style.ncTextColor + horizontalAlignment: Text.AlignHCenter + } + Label { + id: labelMessage + Layout.alignment: Qt.AlignHCenter + Layout.fillWidth: true + Layout.bottomMargin: Style.standardSpacing + text: qsTr("Opening for local editing") + elide: Text.ElideRight + font.pixelSize: root.fontPixelSize + color: Style.ncTextColor + horizontalAlignment: Text.AlignHCenter + } + } +} diff --git a/src/gui/tray/NCBusyIndicator.qml b/src/gui/tray/NCBusyIndicator.qml index c489e5f39..400e274a4 100644 --- a/src/gui/tray/NCBusyIndicator.qml +++ b/src/gui/tray/NCBusyIndicator.qml @@ -22,6 +22,9 @@ BusyIndicator { property color color: Style.ncSecondaryTextColor property string imageSource: "image://svgimage-custom-color/change.svg/" + property int imageSourceSizeWidth: 64 + property int imageSourceSizeHeight: 64 + contentItem: Image { id: contentImage @@ -31,8 +34,8 @@ BusyIndicator { verticalAlignment: Image.AlignVCenter source: colourableImage ? root.imageSource + root.color : root.imageSource - sourceSize.width: 64 - sourceSize.height: 64 + sourceSize.width: root.imageSourceSizeWidth + sourceSize.height: root.imageSourceSizeHeight fillMode: Image.PreserveAspectFit mipmap: true -- cgit v1.2.3