Improve 'Handle local file editing' feature. Add loading popup. Add force sync before opening a file.'

Signed-off-by: alex-z <blackslayer4@gmail.com>
This commit is contained in:
alex-z 2022-09-28 14:26:57 +03:00 committed by Matthieu Gallien
parent 616c85f30f
commit 1e50bd07b0
9 changed files with 159 additions and 9 deletions

View File

@ -34,6 +34,7 @@
<file>src/gui/tray/ActivityItemContent.qml</file>
<file>src/gui/tray/TalkReplyTextField.qml</file>
<file>src/gui/tray/CallNotificationDialog.qml</file>
<file>src/gui/tray/EditFileLocallyLoadingDialog.qml</file>
<file>src/gui/tray/NCBusyIndicator.qml</file>
<file>src/gui/tray/NCToolTip.qml</file>
</qresource>

View File

@ -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<Folder *> &folders,

View File

@ -375,6 +375,8 @@ private:
bool _appRestartRequired = false;
QMap<QString, QMetaObject::Connection> _localFileEditingSyncFinishedConnections;
static FolderMan *_instance;
explicit FolderMan(QObject *parent = nullptr);
friend class OCC::Application;

View File

@ -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;
}

View File

@ -284,6 +284,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) {

View File

@ -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<qlonglong> _callsAlreadyNotified;
QPointer<QObject> _editFileLocallyLoadingDialog;
};
} // namespace OCC

View File

@ -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
}
}
}

View File

@ -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

View File

@ -292,7 +292,7 @@ public:
bool fileCanBeUnlocked(SyncJournalDb * const journal, const QString &folderRelativePath) const;
void setTrustCertificates(bool trustCertificates);
[[nodiscard]] bool trustCertificates() const;
bool trustCertificates() const;
public slots:
/// Used when forgetting credentials