mirror of
https://github.com/nextcloud/desktop.git
synced 2025-10-26 11:17:43 +00:00
fix(file-provider): Removed obsolete settings features in main app.
- Removed materialized items eviction window. - Removed manual enumerator signaling button. - Removed file provider reset button. - Removed progress user interface in file provider settings. Signed-off-by: Iva Horn <iva.horn@nextcloud.com>
This commit is contained in:
parent
467a59e88d
commit
9d2333c4ed
@ -61,8 +61,5 @@
|
|||||||
<file>src/gui/ConflictItemFileInfo.qml</file>
|
<file>src/gui/ConflictItemFileInfo.qml</file>
|
||||||
<file>src/gui/macOS/ui/FileProviderSettings.qml</file>
|
<file>src/gui/macOS/ui/FileProviderSettings.qml</file>
|
||||||
<file>src/gui/macOS/ui/FileProviderFileDelegate.qml</file>
|
<file>src/gui/macOS/ui/FileProviderFileDelegate.qml</file>
|
||||||
<file>src/gui/macOS/ui/FileProviderEvictionDialog.qml</file>
|
|
||||||
<file>src/gui/macOS/ui/FileProviderSyncStatus.qml</file>
|
|
||||||
<file>src/gui/macOS/ui/FileProviderStorageInfo.qml</file>
|
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|||||||
@ -302,17 +302,12 @@ IF( APPLE )
|
|||||||
macOS/fileprovider_mac.mm
|
macOS/fileprovider_mac.mm
|
||||||
macOS/fileproviderdomainmanager.h
|
macOS/fileproviderdomainmanager.h
|
||||||
macOS/fileproviderdomainmanager_mac.mm
|
macOS/fileproviderdomainmanager_mac.mm
|
||||||
macOS/fileproviderdomainsyncstatus.h
|
|
||||||
macOS/fileproviderdomainsyncstatus_mac.mm
|
|
||||||
macOS/fileprovidereditlocallyjob.h
|
macOS/fileprovidereditlocallyjob.h
|
||||||
macOS/fileprovidereditlocallyjob.cpp
|
macOS/fileprovidereditlocallyjob.cpp
|
||||||
macOS/fileprovidereditlocallyjob_mac.mm
|
macOS/fileprovidereditlocallyjob_mac.mm
|
||||||
macOS/fileprovideritemmetadata.h
|
macOS/fileprovideritemmetadata.h
|
||||||
macOS/fileprovideritemmetadata.cpp
|
macOS/fileprovideritemmetadata.cpp
|
||||||
macOS/fileprovideritemmetadata_mac.mm
|
macOS/fileprovideritemmetadata_mac.mm
|
||||||
macOS/fileprovidermaterialiseditemsmodel.h
|
|
||||||
macOS/fileprovidermaterialiseditemsmodel.cpp
|
|
||||||
macOS/fileprovidermaterialiseditemsmodel_mac.mm
|
|
||||||
macOS/fileprovidersettingscontroller.h
|
macOS/fileprovidersettingscontroller.h
|
||||||
macOS/fileprovidersettingscontroller_mac.mm
|
macOS/fileprovidersettingscontroller_mac.mm
|
||||||
macOS/fileprovidersocketcontroller.h
|
macOS/fileprovidersocketcontroller.h
|
||||||
@ -320,8 +315,6 @@ IF( APPLE )
|
|||||||
macOS/fileprovidersocketserver.h
|
macOS/fileprovidersocketserver.h
|
||||||
macOS/fileprovidersocketserver.cpp
|
macOS/fileprovidersocketserver.cpp
|
||||||
macOS/fileprovidersocketserver_mac.mm
|
macOS/fileprovidersocketserver_mac.mm
|
||||||
macOS/fileproviderstorageuseenumerationobserver.h
|
|
||||||
macOS/fileproviderstorageuseenumerationobserver.m
|
|
||||||
macOS/fileproviderutils.h
|
macOS/fileproviderutils.h
|
||||||
macOS/fileproviderutils_mac.mm
|
macOS/fileproviderutils_mac.mm
|
||||||
macOS/fileproviderxpc.h
|
macOS/fileproviderxpc.h
|
||||||
|
|||||||
@ -1,89 +0,0 @@
|
|||||||
/*
|
|
||||||
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
|
|
||||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <QQmlEngine>
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
namespace OCC::Mac
|
|
||||||
{
|
|
||||||
|
|
||||||
class FileProviderDomainSyncStatus : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
QML_ELEMENT
|
|
||||||
QML_UNCREATABLE("FileProviderDomainSyncStatus cannot be instantiated from QML")
|
|
||||||
Q_PROPERTY(bool syncing READ syncing NOTIFY syncingChanged)
|
|
||||||
Q_PROPERTY(bool downloading READ downloading NOTIFY downloadingChanged)
|
|
||||||
Q_PROPERTY(bool uploading READ uploading NOTIFY uploadingChanged)
|
|
||||||
Q_PROPERTY(double fractionCompleted READ fractionCompleted NOTIFY fractionCompletedChanged)
|
|
||||||
Q_PROPERTY(double downloadFractionCompleted READ downloadFractionCompleted NOTIFY downloadFractionCompletedChanged)
|
|
||||||
Q_PROPERTY(double uploadFractionCompleted READ uploadFractionCompleted NOTIFY uploadFractionCompletedChanged)
|
|
||||||
Q_PROPERTY(int downloadFileTotalCount READ downloadFileTotalCount NOTIFY downloadFileTotalCountChanged)
|
|
||||||
Q_PROPERTY(int downloadFileCompletedCount READ downloadFileCompletedCount NOTIFY downloadFileCompletedCountChanged)
|
|
||||||
Q_PROPERTY(int uploadFileTotalCount READ uploadFileTotalCount NOTIFY uploadFileTotalCountChanged)
|
|
||||||
Q_PROPERTY(int uploadFileCompletedCount READ uploadFileCompletedCount NOTIFY uploadFileCompletedCountChanged)
|
|
||||||
// TODO: more detailed reporting (time remaining, megabytes, etc.)
|
|
||||||
Q_PROPERTY(QUrl icon READ icon NOTIFY iconChanged)
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit FileProviderDomainSyncStatus(const QString &domainIdentifier, QObject *parent = nullptr);
|
|
||||||
~FileProviderDomainSyncStatus() override;
|
|
||||||
|
|
||||||
[[nodiscard]] bool syncing() const;
|
|
||||||
[[nodiscard]] bool downloading() const;
|
|
||||||
[[nodiscard]] bool uploading() const;
|
|
||||||
[[nodiscard]] double fractionCompleted() const;
|
|
||||||
[[nodiscard]] double downloadFractionCompleted() const;
|
|
||||||
[[nodiscard]] double uploadFractionCompleted() const;
|
|
||||||
[[nodiscard]] int downloadFileTotalCount() const;
|
|
||||||
[[nodiscard]] int downloadFileCompletedCount() const;
|
|
||||||
[[nodiscard]] int uploadFileTotalCount() const;
|
|
||||||
[[nodiscard]] int uploadFileCompletedCount() const;
|
|
||||||
[[nodiscard]] QUrl icon() const;
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void syncingChanged(bool syncing);
|
|
||||||
void downloadingChanged(bool downloading);
|
|
||||||
void uploadingChanged(bool uploading);
|
|
||||||
void fractionCompletedChanged(double fractionCompleted);
|
|
||||||
void downloadFractionCompletedChanged(double downloadFractionCompleted);
|
|
||||||
void uploadFractionCompletedChanged(double uploadFractionCompleted);
|
|
||||||
void downloadFileTotalCountChanged(int downloadFileTotalCount);
|
|
||||||
void downloadFileCompletedCountChanged(int downloadFileCompletedCount);
|
|
||||||
void uploadFileTotalCountChanged(int uploadFileTotalCount);
|
|
||||||
void uploadFileCompletedCountChanged(int uploadFileCompletedCount);
|
|
||||||
void iconChanged(const QUrl &icon);
|
|
||||||
|
|
||||||
private:
|
|
||||||
void setDownloading(const bool syncing);
|
|
||||||
void setUploading(const bool syncing);
|
|
||||||
void setDownloadFractionCompleted(const double fractionCompleted);
|
|
||||||
void setUploadFractionCompleted(const double fractionCompleted);
|
|
||||||
void setDownloadFileTotalCount(const int fileTotalCount);
|
|
||||||
void setDownloadFileCompletedCount(const int fileCompletedCount);
|
|
||||||
void setUploadFileTotalCount(const int fileTotalCount);
|
|
||||||
void setUploadFileCompletedCount(const int fileCompletedCount);
|
|
||||||
void setIcon(const QUrl &icon);
|
|
||||||
void updateIcon();
|
|
||||||
|
|
||||||
bool _downloading = false;
|
|
||||||
bool _uploading = false;
|
|
||||||
double _downloadFractionCompleted = 0.0;
|
|
||||||
double _uploadFractionCompleted = 0.0;
|
|
||||||
int _downloadFileTotalCount = 0;
|
|
||||||
int _downloadFileCompletedCount = 0;
|
|
||||||
int _uploadFileTotalCount = 0;
|
|
||||||
int _uploadFileCompletedCount = 0;
|
|
||||||
QUrl _icon;
|
|
||||||
|
|
||||||
class MacImplementation;
|
|
||||||
std::unique_ptr<MacImplementation> d;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // OCC::Mac
|
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(OCC::Mac::FileProviderDomainSyncStatus*)
|
|
||||||
@ -1,261 +0,0 @@
|
|||||||
/*
|
|
||||||
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
|
|
||||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "fileproviderdomainsyncstatus.h"
|
|
||||||
|
|
||||||
#include <QLoggingCategory>
|
|
||||||
|
|
||||||
#include "gui/macOS/fileproviderutils.h"
|
|
||||||
#include "libsync/theme.h"
|
|
||||||
|
|
||||||
#import <FileProvider/FileProvider.h>
|
|
||||||
|
|
||||||
#import "gui/macOS/progressobserver.h"
|
|
||||||
|
|
||||||
namespace OCC::Mac
|
|
||||||
{
|
|
||||||
|
|
||||||
Q_LOGGING_CATEGORY(lcMacFileProviderDomainSyncStatus, "nextcloud.gui.macfileproviderdomainsyncstatus", QtInfoMsg)
|
|
||||||
|
|
||||||
class FileProviderDomainSyncStatus::MacImplementation
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit MacImplementation(const QString &domainIdentifier, FileProviderDomainSyncStatus *parent)
|
|
||||||
: q(parent)
|
|
||||||
{
|
|
||||||
_domain = FileProviderUtils::domainForIdentifier(domainIdentifier);
|
|
||||||
_manager = [NSFileProviderManager managerForDomain:_domain];
|
|
||||||
|
|
||||||
if (_manager == nil) {
|
|
||||||
qCWarning(lcMacFileProviderDomainSyncStatus) << "Could not get manager for domain" << domainIdentifier;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
[_manager retain];
|
|
||||||
|
|
||||||
if (@available(macOS 11.3, *)) {
|
|
||||||
NSProgress *const downloadProgress = [_manager globalProgressForKind:NSProgressFileOperationKindDownloading];
|
|
||||||
NSProgress *const uploadProgress = [_manager globalProgressForKind:NSProgressFileOperationKindUploading];
|
|
||||||
_downloadProgressObserver = [[ProgressObserver alloc] initWithProgress:downloadProgress];
|
|
||||||
_uploadProgressObserver = [[ProgressObserver alloc] initWithProgress:uploadProgress];
|
|
||||||
|
|
||||||
_downloadProgressObserver.progressKVOChangeHandler = ^(NSProgress *const progress){
|
|
||||||
updateDownload(progress);
|
|
||||||
};
|
|
||||||
_uploadProgressObserver.progressKVOChangeHandler = ^(NSProgress *const progress){
|
|
||||||
updateUpload(progress);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
~MacImplementation()
|
|
||||||
{
|
|
||||||
[_downloadProgressObserver release];
|
|
||||||
[_uploadProgressObserver release];
|
|
||||||
[_domain release];
|
|
||||||
[_manager release];
|
|
||||||
}
|
|
||||||
|
|
||||||
void updateDownload(NSProgress *const progress) const
|
|
||||||
{
|
|
||||||
qCInfo(lcMacFileProviderDomainSyncStatus) << "Download progress changed" << progress.localizedDescription;
|
|
||||||
if (progress == nil || q == nullptr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
q->setDownloading(!progress.paused && !progress.cancelled && !progress.finished);
|
|
||||||
q->setDownloadFractionCompleted(progress.fractionCompleted);
|
|
||||||
q->setDownloadFileTotalCount(progress.fileTotalCount.intValue);
|
|
||||||
q->setDownloadFileCompletedCount(progress.fileCompletedCount.intValue);
|
|
||||||
q->updateIcon();
|
|
||||||
}
|
|
||||||
|
|
||||||
void updateUpload(NSProgress *const progress) const
|
|
||||||
{
|
|
||||||
qCInfo(lcMacFileProviderDomainSyncStatus) << "Upload progress changed" << progress.localizedDescription;
|
|
||||||
if (progress == nil || q == nullptr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
q->setUploading(!progress.paused && !progress.cancelled && !progress.finished);
|
|
||||||
q->setUploadFractionCompleted(progress.fractionCompleted);
|
|
||||||
q->setUploadFileTotalCount(progress.fileTotalCount.intValue);
|
|
||||||
q->setUploadFileCompletedCount(progress.fileCompletedCount.intValue);
|
|
||||||
q->updateIcon();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
NSFileProviderDomain *_domain = nil;
|
|
||||||
NSFileProviderManager *_manager = nil;
|
|
||||||
ProgressObserver *_downloadProgressObserver = nullptr;
|
|
||||||
ProgressObserver *_uploadProgressObserver = nullptr;
|
|
||||||
FileProviderDomainSyncStatus *q = nullptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
FileProviderDomainSyncStatus::FileProviderDomainSyncStatus(const QString &domainIdentifier, QObject *parent)
|
|
||||||
: QObject(parent)
|
|
||||||
, d(std::make_unique<MacImplementation>(domainIdentifier, this))
|
|
||||||
{
|
|
||||||
qRegisterMetaType<FileProviderDomainSyncStatus*>("FileProviderDomainSyncStatus*");
|
|
||||||
updateIcon();
|
|
||||||
}
|
|
||||||
|
|
||||||
FileProviderDomainSyncStatus::~FileProviderDomainSyncStatus() = default;
|
|
||||||
|
|
||||||
bool FileProviderDomainSyncStatus::syncing() const
|
|
||||||
{
|
|
||||||
return downloading() || uploading();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool FileProviderDomainSyncStatus::downloading() const
|
|
||||||
{
|
|
||||||
return _downloading;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool FileProviderDomainSyncStatus::uploading() const
|
|
||||||
{
|
|
||||||
return _uploading;
|
|
||||||
}
|
|
||||||
|
|
||||||
double FileProviderDomainSyncStatus::fractionCompleted() const
|
|
||||||
{
|
|
||||||
return (downloadFractionCompleted() + uploadFractionCompleted()) / 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
double FileProviderDomainSyncStatus::downloadFractionCompleted() const
|
|
||||||
{
|
|
||||||
return _downloadFractionCompleted;
|
|
||||||
}
|
|
||||||
|
|
||||||
double FileProviderDomainSyncStatus::uploadFractionCompleted() const
|
|
||||||
{
|
|
||||||
return _uploadFractionCompleted;
|
|
||||||
}
|
|
||||||
|
|
||||||
int FileProviderDomainSyncStatus::downloadFileTotalCount() const
|
|
||||||
{
|
|
||||||
return _downloadFileTotalCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
int FileProviderDomainSyncStatus::downloadFileCompletedCount() const
|
|
||||||
{
|
|
||||||
return _downloadFileCompletedCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
int FileProviderDomainSyncStatus::uploadFileTotalCount() const
|
|
||||||
{
|
|
||||||
return _uploadFileTotalCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
int FileProviderDomainSyncStatus::uploadFileCompletedCount() const
|
|
||||||
{
|
|
||||||
return _uploadFileCompletedCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
QUrl FileProviderDomainSyncStatus::icon() const
|
|
||||||
{
|
|
||||||
return _icon;
|
|
||||||
}
|
|
||||||
|
|
||||||
void FileProviderDomainSyncStatus::setDownloading(const bool downloading)
|
|
||||||
{
|
|
||||||
if (_downloading == downloading) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_downloading = downloading;
|
|
||||||
emit downloadingChanged(_downloading);
|
|
||||||
emit syncingChanged(syncing());
|
|
||||||
}
|
|
||||||
|
|
||||||
void FileProviderDomainSyncStatus::setUploading(const bool uploading)
|
|
||||||
{
|
|
||||||
if (_uploading == uploading) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_uploading = uploading;
|
|
||||||
emit uploadingChanged(_uploading);
|
|
||||||
emit syncingChanged(syncing());
|
|
||||||
}
|
|
||||||
|
|
||||||
void FileProviderDomainSyncStatus::setDownloadFractionCompleted(const double downloadFractionCompleted)
|
|
||||||
{
|
|
||||||
if (_downloadFractionCompleted == downloadFractionCompleted) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_downloadFractionCompleted = downloadFractionCompleted;
|
|
||||||
emit downloadFractionCompletedChanged(_downloadFractionCompleted);
|
|
||||||
emit fractionCompletedChanged(fractionCompleted());
|
|
||||||
}
|
|
||||||
|
|
||||||
void FileProviderDomainSyncStatus::setUploadFractionCompleted(const double uploadFractionCompleted)
|
|
||||||
{
|
|
||||||
if (_uploadFractionCompleted == uploadFractionCompleted) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_uploadFractionCompleted = uploadFractionCompleted;
|
|
||||||
emit uploadFractionCompletedChanged(_uploadFractionCompleted);
|
|
||||||
emit fractionCompletedChanged(fractionCompleted());
|
|
||||||
}
|
|
||||||
|
|
||||||
void FileProviderDomainSyncStatus::setDownloadFileTotalCount(const int fileTotalCount)
|
|
||||||
{
|
|
||||||
if (_downloadFileTotalCount == fileTotalCount) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_downloadFileTotalCount = fileTotalCount;
|
|
||||||
emit downloadFileTotalCountChanged(_downloadFileTotalCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FileProviderDomainSyncStatus::setDownloadFileCompletedCount(const int fileCompletedCount)
|
|
||||||
{
|
|
||||||
if (_downloadFileCompletedCount == fileCompletedCount) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_downloadFileCompletedCount = fileCompletedCount;
|
|
||||||
emit downloadFileCompletedCountChanged(_downloadFileCompletedCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FileProviderDomainSyncStatus::setUploadFileTotalCount(const int fileTotalCount)
|
|
||||||
{
|
|
||||||
if (_uploadFileTotalCount == fileTotalCount) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_uploadFileTotalCount = fileTotalCount;
|
|
||||||
emit uploadFileTotalCountChanged(_uploadFileTotalCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FileProviderDomainSyncStatus::setUploadFileCompletedCount(const int fileCompletedCount)
|
|
||||||
{
|
|
||||||
if (_uploadFileCompletedCount == fileCompletedCount) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_uploadFileCompletedCount = fileCompletedCount;
|
|
||||||
emit uploadFileCompletedCountChanged(_uploadFileCompletedCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FileProviderDomainSyncStatus::setIcon(const QUrl &icon)
|
|
||||||
{
|
|
||||||
if (_icon == icon) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_icon = icon;
|
|
||||||
emit iconChanged(_icon);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FileProviderDomainSyncStatus::updateIcon()
|
|
||||||
{
|
|
||||||
const auto iconUrl = syncing() ? Theme::instance()->sync() : Theme::instance()->ok();
|
|
||||||
setIcon(iconUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // OCC::Mac
|
|
||||||
@ -1,166 +0,0 @@
|
|||||||
/*
|
|
||||||
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
|
|
||||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "fileprovidermaterialiseditemsmodel.h"
|
|
||||||
|
|
||||||
#include <QFileInfo>
|
|
||||||
|
|
||||||
namespace OCC {
|
|
||||||
|
|
||||||
namespace Mac {
|
|
||||||
|
|
||||||
FileProviderMaterialisedItemsModel::FileProviderMaterialisedItemsModel(QObject * const parent)
|
|
||||||
: QAbstractListModel(parent)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
int FileProviderMaterialisedItemsModel::rowCount(const QModelIndex &parent) const
|
|
||||||
{
|
|
||||||
if (parent.isValid()) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return _items.count();
|
|
||||||
}
|
|
||||||
|
|
||||||
QVariant FileProviderMaterialisedItemsModel::data(const QModelIndex &index, int role) const
|
|
||||||
{
|
|
||||||
const auto item = _items.at(index.row());
|
|
||||||
|
|
||||||
switch (role) {
|
|
||||||
case Qt::DisplayRole:
|
|
||||||
case FilenameRole:
|
|
||||||
return item.filename();
|
|
||||||
case IdentifierRole:
|
|
||||||
return item.identifier();
|
|
||||||
case ParentItemIdentifierRole:
|
|
||||||
return item.parentItemIdentifier();
|
|
||||||
case DomainIdentifierRole:
|
|
||||||
return item.domainIdentifier();
|
|
||||||
case TypeIdentifierRole:
|
|
||||||
return item.typeIdentifier();
|
|
||||||
case SymlinkTargetPathRole:
|
|
||||||
return item.symlinkTargetPath();
|
|
||||||
case UploadingErrorRole:
|
|
||||||
return item.uploadingError();
|
|
||||||
case DownloadingErrorRole:
|
|
||||||
return item.downloadingError();
|
|
||||||
case MostRecentEditorNameRole:
|
|
||||||
return item.mostRecentEditorName();
|
|
||||||
case OwnerNameRole:
|
|
||||||
return item.ownerName();
|
|
||||||
case ContentModificationDateRole:
|
|
||||||
return item.contentModificationDate();
|
|
||||||
case CreationDateRole:
|
|
||||||
return item.creationDate();
|
|
||||||
case LastUsedDateRole:
|
|
||||||
return item.lastUsedDate();
|
|
||||||
case ContentVersionRole:
|
|
||||||
return item.contentVersion();
|
|
||||||
case MetadataVersionRole:
|
|
||||||
return item.metadataVersion();
|
|
||||||
case TagDataRole:
|
|
||||||
return item.tagData();
|
|
||||||
case CapabilitiesRole:
|
|
||||||
return item.capabilities();
|
|
||||||
case FileSystemFlagsRole:
|
|
||||||
return item.fileSystemFlags();
|
|
||||||
case ChildItemCountRole:
|
|
||||||
return item.childItemCount();
|
|
||||||
case TypeOsCodeRole:
|
|
||||||
return item.typeOsCode();
|
|
||||||
case CreatorOsCodeRole:
|
|
||||||
return item.creatorOsCode();
|
|
||||||
case DocumentSizeRole:
|
|
||||||
return item.documentSize();
|
|
||||||
case MostRecentVersionDownloadedRole:
|
|
||||||
return item.mostRecentVersionDownloaded();
|
|
||||||
case UploadingRole:
|
|
||||||
return item.uploading();
|
|
||||||
case UploadedRole:
|
|
||||||
return item.uploaded();
|
|
||||||
case DownloadingRole:
|
|
||||||
return item.downloading();
|
|
||||||
case DownloadedRole:
|
|
||||||
return item.downloaded();
|
|
||||||
case SharedRole:
|
|
||||||
return item.shared();
|
|
||||||
case SharedByCurrentUserRole:
|
|
||||||
return item.sharedByCurrentUser();
|
|
||||||
case UserVisiblePathRole:
|
|
||||||
return item.userVisiblePath();
|
|
||||||
case FileTypeStringRole:
|
|
||||||
return item.fileTypeString();
|
|
||||||
case FileSizeStringRole:
|
|
||||||
return _locale.formattedDataSize(item.documentSize());
|
|
||||||
}
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
QHash<int, QByteArray> FileProviderMaterialisedItemsModel::roleNames() const
|
|
||||||
{
|
|
||||||
auto roleNames = QAbstractListModel::roleNames();
|
|
||||||
roleNames.insert({
|
|
||||||
{ IdentifierRole, "identifier" },
|
|
||||||
{ ParentItemIdentifierRole, "parentItemIdentifier" },
|
|
||||||
{ DomainIdentifierRole, "domainIdentifier" },
|
|
||||||
{ FilenameRole, "fileName" },
|
|
||||||
{ TypeIdentifierRole, "typeIdentifier" },
|
|
||||||
{ SymlinkTargetPathRole, "symlinkTargetPath" },
|
|
||||||
{ UploadingErrorRole, "uploadingError" },
|
|
||||||
{ DownloadingErrorRole, "downloadingError" },
|
|
||||||
{ MostRecentEditorNameRole, "mostRecentEditorName" },
|
|
||||||
{ OwnerNameRole, "ownerName" },
|
|
||||||
{ ContentModificationDateRole, "contentModificationDate" },
|
|
||||||
{ CreationDateRole, "creationDate" },
|
|
||||||
{ LastUsedDateRole, "lastUsedDate" },
|
|
||||||
{ ContentVersionRole, "contentVersion" },
|
|
||||||
{ MetadataVersionRole, "metadataVersion" },
|
|
||||||
{ TagDataRole, "tagData" },
|
|
||||||
{ CapabilitiesRole, "capabilities" },
|
|
||||||
{ FileSystemFlagsRole, "fileSystemFlags" },
|
|
||||||
{ ChildItemCountRole, "childItemCount" },
|
|
||||||
{ TypeOsCodeRole, "typeOsCode" },
|
|
||||||
{ CreatorOsCodeRole, "creatorOsCode" },
|
|
||||||
{ DocumentSizeRole, "documentSize" },
|
|
||||||
{ MostRecentVersionDownloadedRole, "mostRecentVersionDownloaded" },
|
|
||||||
{ UploadingRole, "uploading" },
|
|
||||||
{ UploadedRole, "uploaded" },
|
|
||||||
{ DownloadingRole, "downloading" },
|
|
||||||
{ DownloadedRole, "downloaded" },
|
|
||||||
{ SharedRole, "shared" },
|
|
||||||
{ SharedByCurrentUserRole, "sharedByCurrentUser" },
|
|
||||||
{ UserVisiblePathRole, "userVisiblePath" },
|
|
||||||
{ FileTypeStringRole, "fileTypeString" },
|
|
||||||
{ FileSizeStringRole, "fileSizeString" },
|
|
||||||
});
|
|
||||||
return roleNames;
|
|
||||||
}
|
|
||||||
|
|
||||||
QVector<FileProviderItemMetadata> FileProviderMaterialisedItemsModel::items() const
|
|
||||||
{
|
|
||||||
return _items;
|
|
||||||
}
|
|
||||||
|
|
||||||
void FileProviderMaterialisedItemsModel::setItems(const QVector<FileProviderItemMetadata> &items)
|
|
||||||
{
|
|
||||||
if (items == _items) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
beginResetModel();
|
|
||||||
// We are using this in the "Free up space" dialog so, sort by size.
|
|
||||||
_items = items;
|
|
||||||
std::ranges::sort(_items, [](const auto &a, const auto &b) {
|
|
||||||
return a.documentSize() > b.documentSize();
|
|
||||||
});
|
|
||||||
endResetModel();
|
|
||||||
|
|
||||||
Q_EMIT itemsChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Mac
|
|
||||||
|
|
||||||
} // namespace OCC
|
|
||||||
@ -1,81 +0,0 @@
|
|||||||
/*
|
|
||||||
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
|
|
||||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QAbstractListModel>
|
|
||||||
#include <QLocale>
|
|
||||||
|
|
||||||
#include "gui/macOS/fileprovideritemmetadata.h"
|
|
||||||
|
|
||||||
namespace OCC {
|
|
||||||
|
|
||||||
namespace Mac {
|
|
||||||
|
|
||||||
class FileProviderMaterialisedItemsModel : public QAbstractListModel
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
Q_PROPERTY(QVector<FileProviderItemMetadata> items READ items WRITE setItems NOTIFY itemsChanged)
|
|
||||||
|
|
||||||
public:
|
|
||||||
enum Roles {
|
|
||||||
IdentifierRole = Qt::UserRole + 1,
|
|
||||||
ParentItemIdentifierRole,
|
|
||||||
DomainIdentifierRole,
|
|
||||||
FilenameRole,
|
|
||||||
TypeIdentifierRole,
|
|
||||||
SymlinkTargetPathRole,
|
|
||||||
UploadingErrorRole,
|
|
||||||
DownloadingErrorRole,
|
|
||||||
MostRecentEditorNameRole,
|
|
||||||
OwnerNameRole,
|
|
||||||
ContentModificationDateRole,
|
|
||||||
CreationDateRole,
|
|
||||||
LastUsedDateRole,
|
|
||||||
ContentVersionRole,
|
|
||||||
MetadataVersionRole,
|
|
||||||
TagDataRole,
|
|
||||||
CapabilitiesRole,
|
|
||||||
FileSystemFlagsRole,
|
|
||||||
ChildItemCountRole,
|
|
||||||
TypeOsCodeRole,
|
|
||||||
CreatorOsCodeRole,
|
|
||||||
DocumentSizeRole,
|
|
||||||
MostRecentVersionDownloadedRole,
|
|
||||||
UploadingRole,
|
|
||||||
UploadedRole,
|
|
||||||
DownloadingRole,
|
|
||||||
DownloadedRole,
|
|
||||||
SharedRole,
|
|
||||||
SharedByCurrentUserRole,
|
|
||||||
UserVisiblePathRole,
|
|
||||||
FileTypeStringRole,
|
|
||||||
FileSizeStringRole,
|
|
||||||
};
|
|
||||||
Q_ENUM(Roles)
|
|
||||||
|
|
||||||
explicit FileProviderMaterialisedItemsModel(QObject *parent = nullptr);
|
|
||||||
[[nodiscard]] int rowCount(const QModelIndex &parent = {}) const override;
|
|
||||||
[[nodiscard]] QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
|
||||||
[[nodiscard]] QHash<int, QByteArray> roleNames() const override;
|
|
||||||
|
|
||||||
[[nodiscard]] QVector<FileProviderItemMetadata> items() const;
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void itemsChanged();
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
void setItems(const QVector<FileProviderItemMetadata> &items);
|
|
||||||
void evictItem(const QString &identifier, const QString &domainIdentifier);
|
|
||||||
|
|
||||||
private:
|
|
||||||
QVector<FileProviderItemMetadata> _items;
|
|
||||||
QLocale _locale;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Mac
|
|
||||||
|
|
||||||
} // namespace OCC
|
|
||||||
@ -1,81 +0,0 @@
|
|||||||
/*
|
|
||||||
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
|
|
||||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "fileprovidermaterialiseditemsmodel.h"
|
|
||||||
|
|
||||||
#include <QLoggingCategory>
|
|
||||||
|
|
||||||
#import <FileProvider/FileProvider.h>
|
|
||||||
|
|
||||||
#include "fileproviderutils.h"
|
|
||||||
|
|
||||||
#include "gui/systray.h"
|
|
||||||
|
|
||||||
namespace OCC {
|
|
||||||
|
|
||||||
namespace Mac {
|
|
||||||
|
|
||||||
Q_LOGGING_CATEGORY(lcMacImplFileProviderMaterialisedItemsModelMac, "nextcloud.gui.macfileprovidermaterialiseditemsmodelmac", QtInfoMsg)
|
|
||||||
|
|
||||||
void FileProviderMaterialisedItemsModel::evictItem(const QString &identifier, const QString &domainIdentifier)
|
|
||||||
{
|
|
||||||
NSFileProviderManager *const manager = FileProviderUtils::managerForDomainIdentifier(domainIdentifier);
|
|
||||||
if (manager == nil) {
|
|
||||||
qCWarning(lcMacImplFileProviderMaterialisedItemsModelMac) << "Received null manager for domain"
|
|
||||||
<< domainIdentifier
|
|
||||||
<< "cannot evict item"
|
|
||||||
<< identifier;
|
|
||||||
Systray::instance()->showMessage(tr("Error"),
|
|
||||||
tr("An internal error occurred. Please try again later."),
|
|
||||||
QSystemTrayIcon::Warning);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
__block BOOL successfullyDeleted = NO;
|
|
||||||
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
|
|
||||||
|
|
||||||
[manager evictItemWithIdentifier:identifier.toNSString() completionHandler:^(NSError *error) {
|
|
||||||
if (error != nil) {
|
|
||||||
const auto errorDesc = QString::fromNSString(error.localizedDescription);
|
|
||||||
qCWarning(lcMacImplFileProviderMaterialisedItemsModelMac) << "Error evicting item:" << errorDesc;
|
|
||||||
Systray::instance()->showMessage(tr("Error"),
|
|
||||||
tr("An error occurred while trying to delete the local copy of this item: %1").arg(errorDesc),
|
|
||||||
QSystemTrayIcon::Warning);
|
|
||||||
} else {
|
|
||||||
successfullyDeleted = YES;
|
|
||||||
}
|
|
||||||
dispatch_semaphore_signal(semaphore);
|
|
||||||
}];
|
|
||||||
|
|
||||||
dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, 3 * NSEC_PER_SEC));
|
|
||||||
[manager release];
|
|
||||||
|
|
||||||
if (successfullyDeleted == NO) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto deletedItemIt = std::find_if(_items.cbegin(),
|
|
||||||
_items.cend(),
|
|
||||||
[identifier, domainIdentifier](const FileProviderItemMetadata &item) {
|
|
||||||
return item.identifier() == identifier && item.domainIdentifier() == domainIdentifier;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (deletedItemIt == _items.cend()) {
|
|
||||||
qCWarning(lcMacImplFileProviderMaterialisedItemsModelMac) << "Could not find item"
|
|
||||||
<< identifier
|
|
||||||
<< "in model items.";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto deletedItemRow = std::distance(_items.cbegin(), deletedItemIt);
|
|
||||||
beginRemoveRows({}, deletedItemRow, deletedItemRow);
|
|
||||||
_items.remove(deletedItemRow);
|
|
||||||
endRemoveRows();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace OCC
|
|
||||||
|
|
||||||
} // namespace Mac
|
|
||||||
@ -8,8 +8,6 @@
|
|||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QtQuickWidgets/QtQuickWidgets>
|
#include <QtQuickWidgets/QtQuickWidgets>
|
||||||
|
|
||||||
#include "gui/macOS/fileproviderdomainsyncstatus.h"
|
|
||||||
|
|
||||||
class QAbstractListModel;
|
class QAbstractListModel;
|
||||||
|
|
||||||
namespace OCC {
|
namespace OCC {
|
||||||
@ -31,30 +29,15 @@ public:
|
|||||||
|
|
||||||
[[nodiscard]] QStringList vfsEnabledAccounts() const;
|
[[nodiscard]] QStringList vfsEnabledAccounts() const;
|
||||||
[[nodiscard]] Q_INVOKABLE bool vfsEnabledForAccount(const QString &userIdAtHost) const;
|
[[nodiscard]] Q_INVOKABLE bool vfsEnabledForAccount(const QString &userIdAtHost) const;
|
||||||
[[nodiscard]] unsigned long long localStorageUsageForAccount(const QString &userIdAtHost) const;
|
|
||||||
[[nodiscard]] Q_INVOKABLE float localStorageUsageGbForAccount(const QString &userIdAtHost) const;
|
|
||||||
[[nodiscard]] unsigned long long remoteStorageUsageForAccount(const QString &userIdAtHost) const;
|
|
||||||
[[nodiscard]] Q_INVOKABLE float remoteStorageUsageGbForAccount(const QString &userIdAtHost) const;
|
|
||||||
[[nodiscard]] Q_INVOKABLE bool trashDeletionEnabledForAccount(const QString &userIdAtHost) const;
|
[[nodiscard]] Q_INVOKABLE bool trashDeletionEnabledForAccount(const QString &userIdAtHost) const;
|
||||||
[[nodiscard]] Q_INVOKABLE bool trashDeletionSetForAccount(const QString &userIdAtHost) const;
|
[[nodiscard]] Q_INVOKABLE bool trashDeletionSetForAccount(const QString &userIdAtHost) const;
|
||||||
|
|
||||||
[[nodiscard]] Q_INVOKABLE QAbstractListModel *materialisedItemsModelForAccount(const QString &userIdAtHost);
|
|
||||||
[[nodiscard]] Q_INVOKABLE FileProviderDomainSyncStatus *domainSyncStatusForAccount(const QString &userIdAtHost) const;
|
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void setVfsEnabledForAccount(const QString &userIdAtHost, const bool setEnabled, const bool showInformationDialog = true);
|
void setVfsEnabledForAccount(const QString &userIdAtHost, const bool setEnabled, const bool showInformationDialog = true);
|
||||||
void setTrashDeletionEnabledForAccount(const QString &userIdAtHost, const bool setEnabled);
|
void setTrashDeletionEnabledForAccount(const QString &userIdAtHost, const bool setEnabled);
|
||||||
void resetVfsForAccount(const QString &userIdAtHost);
|
|
||||||
|
|
||||||
void createEvictionWindowForAccount(const QString &userIdAtHost);
|
|
||||||
void refreshMaterialisedItemsForAccount(const QString &userIdAtHost);
|
|
||||||
void signalFileProviderDomain(const QString &userIdAtHost);
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void vfsEnabledAccountsChanged();
|
void vfsEnabledAccountsChanged();
|
||||||
void localStorageUsageForAccountChanged(const QString &userIdAtHost);
|
|
||||||
void remoteStorageUsageForAccountChanged(const QString &userIdAtHost);
|
|
||||||
void materialisedItemsForAccountChanged(const QString &userIdAtHost);
|
|
||||||
void trashDeletionEnabledForAccountChanged(const QString &userIdAtHost);
|
void trashDeletionEnabledForAccountChanged(const QString &userIdAtHost);
|
||||||
void trashDeletionSetForAccountChanged(const QString &userIdAtHost);
|
void trashDeletionSetForAccountChanged(const QString &userIdAtHost);
|
||||||
|
|
||||||
|
|||||||
@ -12,31 +12,21 @@
|
|||||||
#include "gui/userinfo.h"
|
#include "gui/userinfo.h"
|
||||||
#include "gui/macOS/fileprovider.h"
|
#include "gui/macOS/fileprovider.h"
|
||||||
#include "gui/macOS/fileprovideritemmetadata.h"
|
#include "gui/macOS/fileprovideritemmetadata.h"
|
||||||
#include "gui/macOS/fileprovidermaterialiseditemsmodel.h"
|
|
||||||
#include "gui/macOS/fileproviderutils.h"
|
#include "gui/macOS/fileproviderutils.h"
|
||||||
|
|
||||||
// Objective-C imports
|
// Objective-C imports
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
#import "fileproviderstorageuseenumerationobserver.h"
|
|
||||||
// End of Objective-C imports
|
// End of Objective-C imports
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
constexpr auto fpSettingsQmlPath = "qrc:/qml/src/gui/macOS/ui/FileProviderSettings.qml";
|
constexpr auto fpSettingsQmlPath = "qrc:/qml/src/gui/macOS/ui/FileProviderSettings.qml";
|
||||||
constexpr auto fpEvictionDialogQmlPath = "qrc:/qml/src/gui/macOS/ui/FileProviderEvictionDialog.qml";
|
|
||||||
|
|
||||||
// QML properties -- make sure they match up in QML file!
|
// QML properties -- make sure they match up in QML file!
|
||||||
constexpr auto fpAccountUserIdAtHostProp = "accountUserIdAtHost";
|
constexpr auto fpAccountUserIdAtHostProp = "accountUserIdAtHost";
|
||||||
constexpr auto fpMaterialisedItemsModelProp = "materialisedItemsModel";
|
|
||||||
|
|
||||||
// NSUserDefaults entries
|
// NSUserDefaults entries
|
||||||
constexpr auto enabledAccountsSettingsKey = "enabledAccounts";
|
constexpr auto enabledAccountsSettingsKey = "enabledAccounts";
|
||||||
|
|
||||||
float gbFromBytesWithOneDecimal(const unsigned long long bytes)
|
|
||||||
{
|
|
||||||
constexpr auto bytesIn100Mb = 1ULL * 1000ULL * 1000ULL * 100ULL;
|
|
||||||
return ((bytes * 1.0) / bytesIn100Mb) / 10.0;
|
|
||||||
}
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace OCC {
|
namespace OCC {
|
||||||
@ -57,7 +47,6 @@ public:
|
|||||||
{
|
{
|
||||||
q = parent;
|
q = parent;
|
||||||
initialCheck();
|
initialCheck();
|
||||||
fetchMaterialisedFilesStorageUsage();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
~MacImplementation() override = default;
|
~MacImplementation() override = default;
|
||||||
@ -146,161 +135,18 @@ public:
|
|||||||
return overallActResult;
|
return overallActResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] unsigned long long localStorageUsageForAccount(const QString &userIdAtHost) const
|
|
||||||
{
|
|
||||||
// Return cached value as we fetch asynchronously on initialisation of this class.
|
|
||||||
// We will then emit a signal when the new value is found.
|
|
||||||
return _storageUsage.value(userIdAtHost);
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] QVector<FileProviderItemMetadata> materialisedItemsForAccount(const QString &userIdAtHost) const
|
|
||||||
{
|
|
||||||
return _materialisedFiles.value(userIdAtHost);
|
|
||||||
}
|
|
||||||
|
|
||||||
void signalFileProviderDomain(const QString &userIdAtHost) const
|
|
||||||
{
|
|
||||||
qCInfo(lcFileProviderSettingsController) << "Signalling file provider domain" << userIdAtHost;
|
|
||||||
NSFileProviderDomain * const domain = FileProviderUtils::domainForIdentifier(userIdAtHost);
|
|
||||||
NSFileProviderManager * const manager = [NSFileProviderManager managerForDomain:domain];
|
|
||||||
[domain release];
|
|
||||||
[manager signalEnumeratorForContainerItemIdentifier:NSFileProviderRootContainerItemIdentifier
|
|
||||||
completionHandler:^(NSError *const error) {
|
|
||||||
if (error != nil) {
|
|
||||||
qCWarning(lcFileProviderSettingsController) << "Could not signal file provider domain, error"
|
|
||||||
<< error.localizedDescription;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
qCInfo(lcFileProviderSettingsController) << "Successfully signalled file provider domain";
|
|
||||||
// TODO: Provide some feedback in the UI
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] FileProviderDomainSyncStatus *domainSyncStatusForAccount(const QString &userIdAtHost) const
|
|
||||||
{
|
|
||||||
return _fileProviderDomainSyncStatuses.value(userIdAtHost);
|
|
||||||
}
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
// NOTE: This method will release the provided args so make sure to retain them beforehand
|
|
||||||
void enumerateMaterialisedFilesForDomainManager(NSFileProviderManager * const managerForDomain,
|
|
||||||
NSFileProviderDomain * const domain)
|
|
||||||
{
|
|
||||||
const id<NSFileProviderEnumerator> enumerator = [managerForDomain enumeratorForMaterializedItems];
|
|
||||||
Q_ASSERT(enumerator != nil);
|
|
||||||
[enumerator retain];
|
|
||||||
|
|
||||||
FileProviderStorageUseEnumerationObserver *const storageUseObserver = [[FileProviderStorageUseEnumerationObserver alloc] init];
|
|
||||||
storageUseObserver.enumerationFinishedHandler = ^(NSError *const error) {
|
|
||||||
qCInfo(lcFileProviderSettingsController) << "Enumeration finished for" << domain.identifier;
|
|
||||||
if (error != nil) {
|
|
||||||
qCWarning(lcFileProviderSettingsController) << "Error while enumerating storage use" << error.localizedDescription;
|
|
||||||
[storageUseObserver release];
|
|
||||||
[enumerator release];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto items = storageUseObserver.materialisedItems;
|
|
||||||
Q_ASSERT(items != nil);
|
|
||||||
|
|
||||||
// Remember that OCC::Account::userIdAtHost == domain.identifier for us
|
|
||||||
const auto qDomainIdentifier = QString::fromNSString(domain.identifier);
|
|
||||||
QVector<FileProviderItemMetadata> qMaterialisedItems;
|
|
||||||
qMaterialisedItems.reserve(items.count);
|
|
||||||
unsigned long long storageUsage = 0;
|
|
||||||
for (const id<NSFileProviderItem> item in items) {
|
|
||||||
const auto itemMetadata = FileProviderItemMetadata::fromNSFileProviderItem(item, qDomainIdentifier);
|
|
||||||
storageUsage += itemMetadata.documentSize();
|
|
||||||
qCDebug(lcFileProviderSettingsController) << "Adding item" << itemMetadata.identifier()
|
|
||||||
<< "with size" << itemMetadata.documentSize()
|
|
||||||
<< "to storage usage for account" << qDomainIdentifier
|
|
||||||
<< "with total size" << storageUsage;
|
|
||||||
qMaterialisedItems.append(itemMetadata);
|
|
||||||
}
|
|
||||||
_storageUsage.insert(qDomainIdentifier, storageUsage);
|
|
||||||
_materialisedFiles.insert(qDomainIdentifier, qMaterialisedItems);
|
|
||||||
|
|
||||||
emit q->localStorageUsageForAccountChanged(qDomainIdentifier);
|
|
||||||
emit q->materialisedItemsForAccountChanged(qDomainIdentifier);
|
|
||||||
|
|
||||||
[storageUseObserver release];
|
|
||||||
[enumerator release];
|
|
||||||
|
|
||||||
[managerForDomain release];
|
|
||||||
[domain release];
|
|
||||||
};
|
|
||||||
[enumerator enumerateItemsForObserver:storageUseObserver startingAtPage:NSFileProviderInitialPageSortedByName];
|
|
||||||
}
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void updateDomainSyncStatuses()
|
|
||||||
{
|
|
||||||
qCInfo(lcFileProviderSettingsController) << "Updating file provider domain sync statuses.";
|
|
||||||
_fileProviderDomainSyncStatuses.clear();
|
|
||||||
const auto enabledAccounts = nsEnabledAccounts();
|
|
||||||
|
|
||||||
for (NSString *const accountIdentifier in enabledAccounts) {
|
|
||||||
const auto qAccountIdentifier = QString::fromNSString(accountIdentifier);
|
|
||||||
const auto domainIdentifier = FileProviderUtils::domainIdentifierForAccountIdentifier(accountIdentifier);
|
|
||||||
const auto syncStatus = new FileProviderDomainSyncStatus(domainIdentifier, q);
|
|
||||||
_fileProviderDomainSyncStatuses.insert(qAccountIdentifier, syncStatus);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
[[nodiscard]] NSArray<NSString *> *nsEnabledAccounts() const
|
[[nodiscard]] NSArray<NSString *> *nsEnabledAccounts() const
|
||||||
{
|
{
|
||||||
return (NSArray<NSString *> *)[_userDefaults objectForKey:_accountsKey];
|
return (NSArray<NSString *> *)[_userDefaults objectForKey:_accountsKey];
|
||||||
}
|
}
|
||||||
|
|
||||||
void fetchMaterialisedFilesStorageUsage()
|
|
||||||
{
|
|
||||||
qCInfo(lcFileProviderSettingsController) << "Fetching used storage space of materialized items.";
|
|
||||||
|
|
||||||
[NSFileProviderManager getDomainsWithCompletionHandler: ^(NSArray<NSFileProviderDomain *> *const domains, NSError *const error) {
|
|
||||||
if (error != nil) {
|
|
||||||
qCWarning(lcFileProviderSettingsController) << "Could not get file provider domains:"
|
|
||||||
<< error.localizedDescription
|
|
||||||
<< "Will try again in 2 secs";
|
|
||||||
|
|
||||||
// HACK: Sometimes the system is not in a state where it wants to give us access to
|
|
||||||
// the file provider domains. We will try again in 2 seconds and hope it works
|
|
||||||
const auto thisQobject = (QObject*)this;
|
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
|
||||||
[NSTimer scheduledTimerWithTimeInterval:2 repeats:NO block:^(NSTimer *const timer) {
|
|
||||||
Q_UNUSED(timer)
|
|
||||||
QMetaObject::invokeMethod(thisQobject, [this] { fetchMaterialisedFilesStorageUsage(); });
|
|
||||||
}];
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (NSFileProviderDomain *const domain in domains) {
|
|
||||||
qCInfo(lcFileProviderSettingsController) << "Checking storage use for domain:" << domain.identifier;
|
|
||||||
|
|
||||||
NSFileProviderManager *const managerForDomain = [NSFileProviderManager managerForDomain:domain];
|
|
||||||
if (managerForDomain == nil) {
|
|
||||||
qCWarning(lcFileProviderSettingsController) << "Got a nil file provider manager for domain"
|
|
||||||
<< domain.identifier
|
|
||||||
<< ", returning early.";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
[managerForDomain retain];
|
|
||||||
[domain retain];
|
|
||||||
enumerateMaterialisedFilesForDomainManager(managerForDomain, domain);
|
|
||||||
}
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
void initialCheck()
|
void initialCheck()
|
||||||
{
|
{
|
||||||
qCInfo(lcFileProviderSettingsController) << "Running initial checks for file provider settings controller.";
|
qCInfo(lcFileProviderSettingsController) << "Running initial checks for file provider settings controller.";
|
||||||
NSArray<NSString *> *const vfsEnabledAccounts = nsEnabledAccounts();
|
NSArray<NSString *> *const vfsEnabledAccounts = nsEnabledAccounts();
|
||||||
|
|
||||||
if (vfsEnabledAccounts != nil) {
|
if (vfsEnabledAccounts != nil) {
|
||||||
updateDomainSyncStatuses();
|
|
||||||
connect(q, &FileProviderSettingsController::vfsEnabledAccountsChanged, this, &MacImplementation::updateDomainSyncStatuses);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -313,9 +159,7 @@ private:
|
|||||||
FileProviderSettingsController *q = nullptr;
|
FileProviderSettingsController *q = nullptr;
|
||||||
NSUserDefaults *_userDefaults = NSUserDefaults.standardUserDefaults;
|
NSUserDefaults *_userDefaults = NSUserDefaults.standardUserDefaults;
|
||||||
NSString *_accountsKey = [NSString stringWithUTF8String:enabledAccountsSettingsKey];
|
NSString *_accountsKey = [NSString stringWithUTF8String:enabledAccountsSettingsKey];
|
||||||
QHash<QString, QVector<FileProviderItemMetadata>> _materialisedFiles;
|
|
||||||
QHash<QString, unsigned long long> _storageUsage;
|
QHash<QString, unsigned long long> _storageUsage;
|
||||||
QHash<QString, FileProviderDomainSyncStatus*> _fileProviderDomainSyncStatuses;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
FileProviderSettingsController *FileProviderSettingsController::instance()
|
FileProviderSettingsController *FileProviderSettingsController::instance()
|
||||||
@ -337,9 +181,6 @@ FileProviderSettingsController::FileProviderSettingsController(QObject *parent)
|
|||||||
const auto accountUserIdAtHost = account->userIdAtHostWithPort();
|
const auto accountUserIdAtHost = account->userIdAtHostWithPort();
|
||||||
|
|
||||||
_userInfos.insert(accountUserIdAtHost, userInfo);
|
_userInfos.insert(accountUserIdAtHost, userInfo);
|
||||||
connect(userInfo, &UserInfo::fetchedLastInfo, this, [this, accountUserIdAtHost] {
|
|
||||||
emit remoteStorageUsageForAccountChanged(accountUserIdAtHost);
|
|
||||||
});
|
|
||||||
userInfo->setActive(true);
|
userInfo->setActive(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -383,6 +224,10 @@ void FileProviderSettingsController::setVfsEnabledForAccount(const QString &user
|
|||||||
|
|
||||||
bool FileProviderSettingsController::trashDeletionEnabledForAccount(const QString &userIdAtHost) const
|
bool FileProviderSettingsController::trashDeletionEnabledForAccount(const QString &userIdAtHost) const
|
||||||
{
|
{
|
||||||
|
if (userIdAtHost.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
const auto xpc = FileProvider::instance()->xpc();
|
const auto xpc = FileProvider::instance()->xpc();
|
||||||
|
|
||||||
if (!xpc) {
|
if (!xpc) {
|
||||||
@ -434,140 +279,6 @@ void FileProviderSettingsController::setTrashDeletionEnabledForAccount(const QSt
|
|||||||
emit trashDeletionSetForAccountChanged(userIdAtHost);
|
emit trashDeletionSetForAccountChanged(userIdAtHost);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long long FileProviderSettingsController::localStorageUsageForAccount(const QString &userIdAtHost) const
|
|
||||||
{
|
|
||||||
return d->localStorageUsageForAccount(userIdAtHost);
|
|
||||||
}
|
|
||||||
|
|
||||||
float FileProviderSettingsController::localStorageUsageGbForAccount(const QString &userIdAtHost) const
|
|
||||||
{
|
|
||||||
return gbFromBytesWithOneDecimal(localStorageUsageForAccount(userIdAtHost));
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned long long FileProviderSettingsController::remoteStorageUsageForAccount(const QString &userIdAtHost) const
|
|
||||||
{
|
|
||||||
const auto userInfoForAccount = _userInfos.value(userIdAtHost);
|
|
||||||
if (!userInfoForAccount) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return userInfoForAccount->lastQuotaUsedBytes();
|
|
||||||
}
|
|
||||||
|
|
||||||
float FileProviderSettingsController::remoteStorageUsageGbForAccount(const QString &userIdAtHost) const
|
|
||||||
{
|
|
||||||
return gbFromBytesWithOneDecimal(remoteStorageUsageForAccount(userIdAtHost));
|
|
||||||
}
|
|
||||||
|
|
||||||
QAbstractListModel *FileProviderSettingsController::materialisedItemsModelForAccount(const QString &userIdAtHost)
|
|
||||||
{
|
|
||||||
const auto items = d->materialisedItemsForAccount(userIdAtHost);
|
|
||||||
if (items.isEmpty()) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto model = new FileProviderMaterialisedItemsModel(this);
|
|
||||||
model->setItems(items);
|
|
||||||
|
|
||||||
connect(this, &FileProviderSettingsController::materialisedItemsForAccountChanged,
|
|
||||||
model, [this, model, userIdAtHost](const QString &accountUserIdAtHost) {
|
|
||||||
if (accountUserIdAtHost != userIdAtHost) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto items = d->materialisedItemsForAccount(userIdAtHost);
|
|
||||||
model->setItems(items);
|
|
||||||
});
|
|
||||||
|
|
||||||
return model;
|
|
||||||
}
|
|
||||||
|
|
||||||
void FileProviderSettingsController::createEvictionWindowForAccount(const QString &userIdAtHost)
|
|
||||||
{
|
|
||||||
const auto engine = Systray::instance()->trayEngine();
|
|
||||||
QQmlComponent component(engine, QUrl(fpEvictionDialogQmlPath));
|
|
||||||
const auto model = materialisedItemsModelForAccount(userIdAtHost);
|
|
||||||
const auto genericDialog = component.createWithInitialProperties({
|
|
||||||
{fpAccountUserIdAtHostProp, userIdAtHost},
|
|
||||||
{fpMaterialisedItemsModelProp, QVariant::fromValue(model)},
|
|
||||||
});
|
|
||||||
const auto dialog = qobject_cast<QQuickWindow *>(genericDialog);
|
|
||||||
QObject::connect(dialog, SIGNAL(reloadMaterialisedItems(QString)),
|
|
||||||
this, SLOT(refreshMaterialisedItemsForAccount(QString)));
|
|
||||||
Q_ASSERT(dialog);
|
|
||||||
dialog->show();
|
|
||||||
}
|
|
||||||
|
|
||||||
void FileProviderSettingsController::refreshMaterialisedItemsForAccount(const QString &userIdAtHost)
|
|
||||||
{
|
|
||||||
d->enumerateMaterialisedFilesForDomainManager(FileProviderUtils::managerForDomainIdentifier(userIdAtHost),
|
|
||||||
FileProviderUtils::domainForIdentifier(userIdAtHost));
|
|
||||||
}
|
|
||||||
|
|
||||||
void FileProviderSettingsController::signalFileProviderDomain(const QString &userIdAtHost)
|
|
||||||
{
|
|
||||||
d->signalFileProviderDomain(userIdAtHost);
|
|
||||||
}
|
|
||||||
|
|
||||||
FileProviderDomainSyncStatus *FileProviderSettingsController::domainSyncStatusForAccount(const QString &userIdAtHost) const
|
|
||||||
{
|
|
||||||
return d->domainSyncStatusForAccount(userIdAtHost);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FileProviderSettingsController::resetVfsForAccount(const QString &userIdAtHost)
|
|
||||||
{
|
|
||||||
qCInfo(lcFileProviderSettingsController) << "Resetting virtual files environment for account" << userIdAtHost;
|
|
||||||
setVfsEnabledForAccount(userIdAtHost, false);
|
|
||||||
|
|
||||||
const auto accountState = AccountManager::instance()->accountFromUserId(userIdAtHost);
|
|
||||||
if (!accountState) {
|
|
||||||
qCWarning(lcFileProviderSettingsController) << "Could not find account for userIdAtHost" << userIdAtHost
|
|
||||||
<< "to reset VFS environment.";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const auto splitUserId = userIdAtHost.split('@');
|
|
||||||
if (splitUserId.size() != 2) {
|
|
||||||
qCWarning(lcFileProviderSettingsController) << "Invalid userIdAtHost format" << userIdAtHost
|
|
||||||
<< "Expected format: userId@host";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const auto accUserId = splitUserId.at(0);
|
|
||||||
const auto accHost = splitUserId.at(1);
|
|
||||||
|
|
||||||
// Delete the database in the group container
|
|
||||||
const auto groupContainerPath = FileProviderUtils::groupContainerPath();
|
|
||||||
if (groupContainerPath.isEmpty()) {
|
|
||||||
qCWarning(lcFileProviderSettingsController) << "Could not determine group container path, cannot reset VFS.";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const auto dbsPath = QDir::cleanPath(groupContainerPath + "/FileProviderExt/Database");
|
|
||||||
qCInfo(lcFileProviderSettingsController) << "Resetting VFS for account" << userIdAtHost
|
|
||||||
<< "by deleting database files in" << dbsPath;
|
|
||||||
const auto databases = QDir(dbsPath).entryList(QDir::Files);
|
|
||||||
for (const auto &dbFile : databases) {
|
|
||||||
// Format of db file names is "userId_cloud_nc_com-fileproviderextdatabase.realm"
|
|
||||||
const auto splitDbName = dbFile.split('-');
|
|
||||||
const auto address = splitDbName.at(0).split('_').mid(1).join('.');
|
|
||||||
const auto userId = splitDbName.at(0).split('_').first();
|
|
||||||
|
|
||||||
if (userId != accUserId || address != accHost) {
|
|
||||||
qCInfo(lcFileProviderSettingsController) << "Skipping database file" << dbFile
|
|
||||||
<< "for userId" << userId
|
|
||||||
<< "and host" << address
|
|
||||||
<< "as it does not match the account we are resetting.";
|
|
||||||
continue; // Not the database we are looking for
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto dbPath = QDir(dbsPath).filePath(dbFile);
|
|
||||||
qCInfo(lcFileProviderSettingsController) << "Deleting database file" << dbPath;
|
|
||||||
if (QFile::exists(dbPath)) {
|
|
||||||
QFile::remove(dbPath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setVfsEnabledForAccount(userIdAtHost, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Mac
|
} // namespace Mac
|
||||||
|
|
||||||
} // namespace OCC
|
} // namespace OCC
|
||||||
|
|||||||
@ -1,16 +0,0 @@
|
|||||||
/*
|
|
||||||
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
|
|
||||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
|
||||||
#import <FileProvider/FileProvider.h>
|
|
||||||
|
|
||||||
typedef void(^UsageEnumerationFinishedHandler)(NSError *const error);
|
|
||||||
|
|
||||||
@interface FileProviderStorageUseEnumerationObserver : NSObject<NSFileProviderEnumerationObserver>
|
|
||||||
|
|
||||||
@property (readwrite, strong) UsageEnumerationFinishedHandler enumerationFinishedHandler;
|
|
||||||
@property (readonly) NSSet<id<NSFileProviderItem>> *materialisedItems;
|
|
||||||
|
|
||||||
@end
|
|
||||||
@ -1,47 +0,0 @@
|
|||||||
/*
|
|
||||||
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
|
|
||||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import "fileproviderstorageuseenumerationobserver.h"
|
|
||||||
|
|
||||||
@implementation FileProviderStorageUseEnumerationObserver
|
|
||||||
|
|
||||||
- (instancetype)init
|
|
||||||
{
|
|
||||||
self = [super init];
|
|
||||||
if (self) {
|
|
||||||
_materialisedItems = [NSSet set];
|
|
||||||
}
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
// NSFileProviderEnumerationObserver protocol methods
|
|
||||||
- (void)didEnumerateItems:(NSArray<id<NSFileProviderItem>> *)updatedItems
|
|
||||||
{
|
|
||||||
NSMutableSet<id<NSFileProviderItem>> * const existingItems = self.materialisedItems.mutableCopy;
|
|
||||||
|
|
||||||
for (const id<NSFileProviderItem> item in updatedItems) {
|
|
||||||
NSLog(@"StorageUseEnumerationObserver: Enumerating %@ with size %llu",
|
|
||||||
item.filename, item.documentSize.unsignedLongLongValue);
|
|
||||||
[existingItems addObject:item];
|
|
||||||
}
|
|
||||||
|
|
||||||
_materialisedItems = existingItems.copy;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)finishEnumeratingWithError:(NSError *)error
|
|
||||||
{
|
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
|
||||||
self.enumerationFinishedHandler(error);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)finishEnumeratingUpToPage:(NSFileProviderPage)nextPage
|
|
||||||
{
|
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
|
||||||
self.enumerationFinishedHandler(nil);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
@ -1,72 +0,0 @@
|
|||||||
/*
|
|
||||||
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
|
|
||||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
*/
|
|
||||||
|
|
||||||
import QtQuick 2.15
|
|
||||||
import QtQuick.Controls 2.15
|
|
||||||
import QtQuick.Layouts 1.15
|
|
||||||
|
|
||||||
import Style 1.0
|
|
||||||
import "../../filedetails"
|
|
||||||
import "../../tray"
|
|
||||||
|
|
||||||
import com.nextcloud.desktopclient 1.0
|
|
||||||
|
|
||||||
ApplicationWindow {
|
|
||||||
id: root
|
|
||||||
|
|
||||||
signal reloadMaterialisedItems(string accountUserIdAtHost)
|
|
||||||
|
|
||||||
property var materialisedItemsModel: null
|
|
||||||
property string accountUserIdAtHost: ""
|
|
||||||
|
|
||||||
LayoutMirroring.enabled: Application.layoutDirection === Qt.RightToLeft
|
|
||||||
LayoutMirroring.childrenInherit: true
|
|
||||||
|
|
||||||
title: qsTr("Remove local copies")
|
|
||||||
color: palette.base
|
|
||||||
flags: Qt.Dialog | Qt.WindowStaysOnTopHint
|
|
||||||
width: 640
|
|
||||||
height: 480
|
|
||||||
|
|
||||||
Component.onCompleted: reloadMaterialisedItems(accountUserIdAtHost)
|
|
||||||
|
|
||||||
ColumnLayout {
|
|
||||||
anchors.fill: parent
|
|
||||||
|
|
||||||
RowLayout {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.margins: Style.standardSpacing
|
|
||||||
|
|
||||||
EnforcedPlainTextLabel {
|
|
||||||
text: qsTr("Local copies")
|
|
||||||
font.bold: true
|
|
||||||
font.pointSize: Style.headerFontPtSize
|
|
||||||
Layout.fillWidth: true
|
|
||||||
}
|
|
||||||
|
|
||||||
Button {
|
|
||||||
padding: Style.smallSpacing
|
|
||||||
text: qsTr("Reload")
|
|
||||||
onClicked: reloadMaterialisedItems(accountUserIdAtHost)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ListView {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.fillHeight: true
|
|
||||||
|
|
||||||
Layout.leftMargin: Style.standardSpacing
|
|
||||||
Layout.rightMargin: Style.standardSpacing
|
|
||||||
|
|
||||||
clip: true
|
|
||||||
model: root.materialisedItemsModel
|
|
||||||
delegate: FileProviderFileDelegate {
|
|
||||||
width: parent.width
|
|
||||||
height: 60
|
|
||||||
onEvictItem: root.materialisedItemsModel.evictItem(identifier, domainIdentifier)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -53,63 +53,11 @@ Page {
|
|||||||
checked: root.controller.vfsEnabledForAccount(root.accountUserIdAtHost)
|
checked: root.controller.vfsEnabledForAccount(root.accountUserIdAtHost)
|
||||||
onClicked: root.controller.setVfsEnabledForAccount(root.accountUserIdAtHost, checked)
|
onClicked: root.controller.setVfsEnabledForAccount(root.accountUserIdAtHost, checked)
|
||||||
}
|
}
|
||||||
|
|
||||||
Loader {
|
CheckBox {
|
||||||
id: vfsSettingsLoader
|
text: qsTr("Allow deletion of items in Trash")
|
||||||
|
checked: root.controller.trashDeletionEnabledForAccount(root.accountUserIdAtHost)
|
||||||
Layout.fillWidth: true
|
onClicked: root.controller.setTrashDeletionEnabledForAccount(root.accountUserIdAtHost, checked)
|
||||||
Layout.fillHeight: true
|
|
||||||
|
|
||||||
active: vfsEnabledCheckBox.checked
|
|
||||||
sourceComponent: ColumnLayout {
|
|
||||||
Rectangle {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
height: Style.normalBorderWidth
|
|
||||||
color: palette.dark
|
|
||||||
}
|
|
||||||
|
|
||||||
FileProviderSyncStatus {
|
|
||||||
syncStatus: root.controller.domainSyncStatusForAccount(root.accountUserIdAtHost)
|
|
||||||
onDomainSignalRequested: root.controller.signalFileProviderDomain(root.accountUserIdAtHost)
|
|
||||||
}
|
|
||||||
|
|
||||||
FileProviderStorageInfo {
|
|
||||||
id: storageInfo
|
|
||||||
localUsedStorage: root.controller.localStorageUsageGbForAccount(root.accountUserIdAtHost)
|
|
||||||
remoteUsedStorage: root.controller.remoteStorageUsageGbForAccount(root.accountUserIdAtHost)
|
|
||||||
|
|
||||||
onEvictDialogRequested: root.controller.createEvictionWindowForAccount(root.accountUserIdAtHost)
|
|
||||||
|
|
||||||
Connections {
|
|
||||||
target: root.controller
|
|
||||||
|
|
||||||
function onLocalStorageUsageForAccountChanged(accountUserIdAtHost) {
|
|
||||||
if (root.accountUserIdAtHost !== accountUserIdAtHost) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
storageInfo.localUsedStorage = root.controller.localStorageUsageGbForAccount(root.accountUserIdAtHost);
|
|
||||||
}
|
|
||||||
|
|
||||||
function onRemoteStorageUsageForAccountChanged(accountUserIdAtHost) {
|
|
||||||
if (root.accountUserIdAtHost !== accountUserIdAtHost) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
storageInfo.remoteUsedStorage = root.controller.remoteStorageUsageGbForAccount(root.accountUserIdAtHost);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CheckBox {
|
|
||||||
text: qsTr("Allow deletion of items in Trash")
|
|
||||||
checked: root.controller.trashDeletionEnabledForAccount(root.accountUserIdAtHost)
|
|
||||||
onClicked: root.controller.setTrashDeletionEnabledForAccount(root.accountUserIdAtHost, checked)
|
|
||||||
}
|
|
||||||
|
|
||||||
Button {
|
|
||||||
text: qsTr("Reset virtual files environment")
|
|
||||||
onPressed: root.controller.resetVfsForAccount(root.accountUserIdAtHost);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,60 +0,0 @@
|
|||||||
/*
|
|
||||||
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
|
|
||||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
*/
|
|
||||||
|
|
||||||
import QtQuick 2.15
|
|
||||||
import QtQuick.Controls 2.15
|
|
||||||
import QtQuick.Layouts 1.15
|
|
||||||
|
|
||||||
import Style 1.0
|
|
||||||
import "../../filedetails"
|
|
||||||
import "../../tray"
|
|
||||||
|
|
||||||
import com.nextcloud.desktopclient 1.0
|
|
||||||
|
|
||||||
GridLayout {
|
|
||||||
id: root
|
|
||||||
|
|
||||||
signal evictDialogRequested()
|
|
||||||
|
|
||||||
required property real localUsedStorage
|
|
||||||
required property real remoteUsedStorage
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
columns: 3
|
|
||||||
|
|
||||||
EnforcedPlainTextLabel {
|
|
||||||
Layout.row: 0
|
|
||||||
Layout.column: 0
|
|
||||||
Layout.alignment: Layout.AlignLeft | Layout.AlignVCenter
|
|
||||||
text: qsTr("Local storage use")
|
|
||||||
font.bold: true
|
|
||||||
}
|
|
||||||
|
|
||||||
EnforcedPlainTextLabel {
|
|
||||||
Layout.row: 0
|
|
||||||
Layout.column: 1
|
|
||||||
Layout.alignment: Layout.AlignRight | Layout.AlignVCenter
|
|
||||||
Layout.fillWidth: true
|
|
||||||
text: qsTr("%1 GB of %2 GB remote files synced").arg(root.localUsedStorage.toFixed(2)).arg(root.remoteUsedStorage.toFixed(2));
|
|
||||||
elide: Text.ElideRight
|
|
||||||
color: palette.dark
|
|
||||||
horizontalAlignment: Text.AlignRight
|
|
||||||
}
|
|
||||||
|
|
||||||
Button {
|
|
||||||
Layout.row: 0
|
|
||||||
Layout.column: 2
|
|
||||||
Layout.alignment: Layout.AlignRight | Layout.AlignVCenter
|
|
||||||
text: qsTr("Free up space …")
|
|
||||||
onPressed: root.evictDialogRequested()
|
|
||||||
}
|
|
||||||
|
|
||||||
ProgressBar {
|
|
||||||
Layout.row: 1
|
|
||||||
Layout.columnSpan: root.columns
|
|
||||||
Layout.fillWidth: true
|
|
||||||
value: root.localUsedStorage / root.remoteUsedStorage
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,71 +0,0 @@
|
|||||||
/*
|
|
||||||
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
|
|
||||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
*/
|
|
||||||
|
|
||||||
import QtQuick 2.15
|
|
||||||
import QtQuick.Controls 2.15
|
|
||||||
import QtQuick.Layouts 1.15
|
|
||||||
|
|
||||||
import Style 1.0
|
|
||||||
import "../../filedetails"
|
|
||||||
import "../../tray"
|
|
||||||
|
|
||||||
import com.nextcloud.desktopclient 1.0
|
|
||||||
|
|
||||||
GridLayout {
|
|
||||||
id: root
|
|
||||||
|
|
||||||
signal domainSignalRequested
|
|
||||||
required property var syncStatus
|
|
||||||
|
|
||||||
rows: syncStatus.syncing ? 2 : 1
|
|
||||||
|
|
||||||
NCBusyIndicator {
|
|
||||||
id: syncIcon
|
|
||||||
|
|
||||||
property int size: Style.trayListItemIconSize * 0.8
|
|
||||||
|
|
||||||
Layout.row: 0
|
|
||||||
Layout.rowSpan: root.syncStatus.syncing ? 2 : 1
|
|
||||||
Layout.column: 0
|
|
||||||
Layout.preferredWidth: size
|
|
||||||
Layout.preferredHeight: size
|
|
||||||
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
|
|
||||||
|
|
||||||
padding: 0
|
|
||||||
spacing: 0
|
|
||||||
imageSource: root.syncStatus.icon
|
|
||||||
running: false // avoid rotating the icon when syncing
|
|
||||||
}
|
|
||||||
|
|
||||||
EnforcedPlainTextLabel {
|
|
||||||
Layout.row: 0
|
|
||||||
Layout.column: 1
|
|
||||||
Layout.columnSpan: root.syncStatus.syncing ? 2 : 1
|
|
||||||
Layout.fillWidth: true
|
|
||||||
font.bold: true
|
|
||||||
font.pointSize: Style.headerFontPtSize
|
|
||||||
text: root.syncStatus.syncing ? qsTr("Syncing") : qsTr("All synced!")
|
|
||||||
}
|
|
||||||
|
|
||||||
NCProgressBar {
|
|
||||||
Layout.row: 1
|
|
||||||
Layout.column: 1
|
|
||||||
Layout.fillWidth: true
|
|
||||||
value: root.syncStatus.fractionCompleted
|
|
||||||
visible: root.syncStatus.syncing
|
|
||||||
}
|
|
||||||
|
|
||||||
Button {
|
|
||||||
id: requestSyncButton
|
|
||||||
text: qsTr("Request sync")
|
|
||||||
visible: !root.syncStatus.syncing
|
|
||||||
hoverEnabled: true
|
|
||||||
onClicked: root.domainSignalRequested()
|
|
||||||
|
|
||||||
ToolTip.visible: hovered
|
|
||||||
ToolTip.delay: Qt.styleHints.mousePressAndHoldInterval
|
|
||||||
ToolTip.text: qsTr("Request a sync of changes for the VFS environment.\nmacOS may ignore or delay this request.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -332,53 +332,6 @@
|
|||||||
<source>Allow deletion of items in Trash</source>
|
<source>Allow deletion of items in Trash</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<location filename="../src/gui/macOS/ui/FileProviderSettings.qml" line="109"/>
|
|
||||||
<source>Reset virtual files environment</source>
|
|
||||||
<translation type="unfinished"></translation>
|
|
||||||
</message>
|
|
||||||
</context>
|
|
||||||
<context>
|
|
||||||
<name>FileProviderStorageInfo</name>
|
|
||||||
<message>
|
|
||||||
<location filename="../src/gui/macOS/ui/FileProviderStorageInfo.qml" line="31"/>
|
|
||||||
<source>Local storage use</source>
|
|
||||||
<translation type="unfinished"></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<location filename="../src/gui/macOS/ui/FileProviderStorageInfo.qml" line="40"/>
|
|
||||||
<source>%1 GB of %2 GB remote files synced</source>
|
|
||||||
<translation type="unfinished"></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<location filename="../src/gui/macOS/ui/FileProviderStorageInfo.qml" line="50"/>
|
|
||||||
<source>Free up space …</source>
|
|
||||||
<translation type="unfinished"></translation>
|
|
||||||
</message>
|
|
||||||
</context>
|
|
||||||
<context>
|
|
||||||
<name>FileProviderSyncStatus</name>
|
|
||||||
<message>
|
|
||||||
<location filename="../src/gui/macOS/ui/FileProviderSyncStatus.qml" line="49"/>
|
|
||||||
<source>Syncing</source>
|
|
||||||
<translation type="unfinished"></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<location filename="../src/gui/macOS/ui/FileProviderSyncStatus.qml" line="49"/>
|
|
||||||
<source>All synced!</source>
|
|
||||||
<translation type="unfinished"></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<location filename="../src/gui/macOS/ui/FileProviderSyncStatus.qml" line="62"/>
|
|
||||||
<source>Request sync</source>
|
|
||||||
<translation type="unfinished"></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<location filename="../src/gui/macOS/ui/FileProviderSyncStatus.qml" line="69"/>
|
|
||||||
<source>Request a sync of changes for the VFS environment.
|
|
||||||
macOS may ignore or delay this request.</source>
|
|
||||||
<translation type="unfinished"></translation>
|
|
||||||
</message>
|
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>FileSystem</name>
|
<name>FileSystem</name>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user