mirror of
https://github.com/nextcloud/desktop.git
synced 2024-11-21 20:45:51 +03:00
Implement missing share settings
Signed-off-by: alex-z <blackslayer4@gmail.com>
This commit is contained in:
parent
7edc0a43a6
commit
f39a0903c5
12 changed files with 420 additions and 62 deletions
|
@ -51,5 +51,6 @@
|
|||
<file>src/gui/tray/EnforcedPlainTextLabel.qml</file>
|
||||
<file>theme/Style/Style.qml</file>
|
||||
<file>theme/Style/qmldir</file>
|
||||
<file>src/gui/filedetails/NCRadioButton.qml</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
|
43
src/gui/filedetails/NCRadioButton.qml
Normal file
43
src/gui/filedetails/NCRadioButton.qml
Normal file
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright (C) by Oleksandr Zolotov <alex@nextcloud.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
import Style 1.0
|
||||
|
||||
RadioButton {
|
||||
id: root
|
||||
property int indicatorItemWidth: Style.radioButtonIndicatorSize
|
||||
property int indicatorItemHeight: Style.radioButtonIndicatorSize
|
||||
property string color: Style.ncTextColor
|
||||
readonly property int radius: Style.radioButtonCustomRadius
|
||||
|
||||
indicator: Rectangle {
|
||||
implicitWidth: root.indicatorItemWidth
|
||||
implicitHeight: root.indicatorItemHeight
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Style.radioButtonCustomMarginLeftOuter
|
||||
radius: root.radius
|
||||
border.color: root.color
|
||||
border.width: Style.normalBorderWidth
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
visible: root.checked
|
||||
color: root.color
|
||||
radius: root.radius
|
||||
anchors.margins: Style.radioButtonCustomMarginLeftInner
|
||||
}
|
||||
}
|
||||
}
|
|
@ -33,11 +33,13 @@ GridLayout {
|
|||
signal resetPasswordField
|
||||
signal showPasswordSetError(string errorMessage);
|
||||
|
||||
signal toggleHideDownload(bool enable)
|
||||
signal toggleAllowEditing(bool enable)
|
||||
signal toggleAllowResharing(bool enable)
|
||||
signal togglePasswordProtect(bool enable)
|
||||
signal toggleExpirationDate(bool enable)
|
||||
signal toggleNoteToRecipient(bool enable)
|
||||
signal permissionModeChanged(int permissionMode)
|
||||
|
||||
signal setLinkShareLabel(string label)
|
||||
signal setExpireDate(var milliseconds) // Since QML ints are only 32 bits, use a variant
|
||||
|
@ -236,9 +238,11 @@ GridLayout {
|
|||
|
||||
onToggleAllowEditing: root.toggleAllowEditing(enable)
|
||||
onToggleAllowResharing: root.toggleAllowResharing(enable)
|
||||
onToggleHideDownload: root.toggleHideDownload(enable)
|
||||
onTogglePasswordProtect: root.togglePasswordProtect(enable)
|
||||
onToggleExpirationDate: root.toggleExpirationDate(enable)
|
||||
onToggleNoteToRecipient: root.toggleNoteToRecipient(enable)
|
||||
onPermissionModeChanged: root.permissionModeChanged(permissionMode)
|
||||
|
||||
onSetLinkShareLabel: root.setLinkShareLabel(label)
|
||||
onSetExpireDate: root.setExpireDate(milliseconds) // Since QML ints are only 32 bits, use a variant
|
||||
|
|
|
@ -32,9 +32,11 @@ Page {
|
|||
|
||||
signal toggleAllowEditing(bool enable)
|
||||
signal toggleAllowResharing(bool enable)
|
||||
signal toggleHideDownload(bool enable)
|
||||
signal togglePasswordProtect(bool enable)
|
||||
signal toggleExpirationDate(bool enable)
|
||||
signal toggleNoteToRecipient(bool enable)
|
||||
signal permissionModeChanged(int permissionMode)
|
||||
|
||||
signal setLinkShareLabel(string label)
|
||||
signal setExpireDate(var milliseconds) // Since QML ints are only 32 bits, use a variant
|
||||
|
@ -65,16 +67,21 @@ Page {
|
|||
readonly property string linkShareLabel: shareModelData.linkShareLabel ?? ""
|
||||
|
||||
readonly property bool editingAllowed: shareModelData.editingAllowed
|
||||
readonly property bool hideDownload: shareModelData.hideDownload
|
||||
readonly property bool noteEnabled: shareModelData.noteEnabled
|
||||
readonly property bool expireDateEnabled: shareModelData.expireDateEnabled
|
||||
readonly property bool expireDateEnforced: shareModelData.expireDateEnforced
|
||||
readonly property bool passwordProtectEnabled: shareModelData.passwordProtectEnabled
|
||||
readonly property bool passwordEnforced: shareModelData.passwordEnforced
|
||||
readonly property bool isSecureFileDropLink: shareModelData.isSecureFileDropLink
|
||||
readonly property bool isSharePermissionChangeInProgress: shareModelData.isSharePermissionChangeInProgress
|
||||
readonly property bool isHideDownloadInProgress: shareModelData.isHideDownloadInProgress
|
||||
readonly property int currentPermissionMode: shareModelData.currentPermissionMode
|
||||
|
||||
readonly property bool isLinkShare: shareModelData.shareType === ShareModel.ShareTypeLink
|
||||
|
||||
property bool waitingForEditingAllowedChange: false
|
||||
readonly property bool isFolderItem: shareModelData.sharedItemType === ShareModel.SharedItemTypeFolder
|
||||
readonly property bool isEncryptedItem: shareModelData.sharedItemType === ShareModel.SharedItemTypeEncryptedFile || shareModelData.sharedItemType === ShareModel.SharedItemTypeEncryptedFolder || shareModelData.sharedItemType === ShareModel.SharedItemTypeEncryptedTopLevelFolder
|
||||
|
||||
property bool waitingForNoteEnabledChange: false
|
||||
property bool waitingForExpireDateEnabledChange: false
|
||||
property bool waitingForPasswordProtectEnabledChange: false
|
||||
|
@ -108,11 +115,6 @@ Page {
|
|||
waitingForExpireDateChange = false;
|
||||
}
|
||||
|
||||
function resetEditingAllowedField() {
|
||||
editingAllowedMenuItem.checked = editingAllowed;
|
||||
waitingForEditingAllowedChange = false;
|
||||
}
|
||||
|
||||
function resetNoteEnabledField() {
|
||||
noteEnabledMenuItem.checked = noteEnabled;
|
||||
waitingForNoteEnabledChange = false;
|
||||
|
@ -135,8 +137,6 @@ Page {
|
|||
resetPasswordField();
|
||||
resetLinkShareLabelField();
|
||||
resetExpireDateField();
|
||||
|
||||
resetEditingAllowedField();
|
||||
resetNoteEnabledField();
|
||||
resetExpireDateEnabledField();
|
||||
resetPasswordProtectEnabledField();
|
||||
|
@ -154,8 +154,6 @@ Page {
|
|||
onPasswordChanged: resetPasswordField()
|
||||
onLinkShareLabelChanged: resetLinkShareLabelField()
|
||||
onExpireDateChanged: resetExpireDateField()
|
||||
|
||||
onEditingAllowedChanged: resetEditingAllowedField()
|
||||
onNoteEnabledChanged: resetNoteEnabledField()
|
||||
onExpireDateEnabledChanged: resetExpireDateEnabledField()
|
||||
onPasswordProtectEnabledChanged: resetPasswordProtectEnabledField()
|
||||
|
@ -313,34 +311,124 @@ Page {
|
|||
}
|
||||
}
|
||||
|
||||
// On these checkables, the clicked() signal is called after
|
||||
// the check state changes.
|
||||
CheckBox {
|
||||
id: editingAllowedMenuItem
|
||||
Loader {
|
||||
Layout.fillWidth: true
|
||||
active: !root.isFolderItem && !root.isEncryptedItem
|
||||
visible: active
|
||||
sourceComponent: CheckBox {
|
||||
spacing: moreMenu.indicatorSpacing
|
||||
padding: moreMenu.itemPadding
|
||||
indicator.width: moreMenu.indicatorItemWidth
|
||||
indicator.height: moreMenu.indicatorItemWidth
|
||||
|
||||
checkable: true
|
||||
checked: root.editingAllowed
|
||||
text: qsTr("Allow upload and editing")
|
||||
enabled: !root.isSharePermissionChangeInProgress
|
||||
|
||||
onClicked: root.toggleAllowEditing(checked)
|
||||
|
||||
NCBusyIndicator {
|
||||
anchors.fill: parent
|
||||
visible: root.isSharePermissionChangeInProgress
|
||||
running: visible
|
||||
z: 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
Layout.fillWidth: true
|
||||
active: root.isFolderItem && !root.isEncryptedItem
|
||||
visible: active
|
||||
sourceComponent: ColumnLayout {
|
||||
id: permissionRadioButtonsLayout
|
||||
spacing: 0
|
||||
width: parent.width
|
||||
|
||||
ButtonGroup {
|
||||
id: permissionModeRadioButtonsGroup
|
||||
}
|
||||
|
||||
NCRadioButton {
|
||||
readonly property int permissionMode: ShareModel.ModeViewOnly
|
||||
Layout.fillWidth: true
|
||||
ButtonGroup.group: permissionModeRadioButtonsGroup
|
||||
enabled: !root.isSharePermissionChangeInProgress
|
||||
checked: root.currentPermissionMode === permissionMode
|
||||
text: qsTr("View only")
|
||||
indicatorItemWidth: moreMenu.indicatorItemWidth
|
||||
indicatorItemHeight: moreMenu.indicatorItemWidth
|
||||
spacing: moreMenu.indicatorSpacing
|
||||
padding: moreMenu.itemPadding
|
||||
onClicked: root.permissionModeChanged(permissionMode)
|
||||
}
|
||||
|
||||
NCRadioButton {
|
||||
readonly property int permissionMode: ShareModel.ModeUploadAndEditing
|
||||
Layout.fillWidth: true
|
||||
ButtonGroup.group: permissionModeRadioButtonsGroup
|
||||
enabled: !root.isSharePermissionChangeInProgress
|
||||
checked: root.currentPermissionMode === permissionMode
|
||||
text: qsTr("Allow upload and editing")
|
||||
indicatorItemWidth: moreMenu.indicatorItemWidth
|
||||
indicatorItemHeight: moreMenu.indicatorItemWidth
|
||||
spacing: moreMenu.indicatorSpacing
|
||||
padding: moreMenu.itemPadding
|
||||
onClicked: root.permissionModeChanged(permissionMode)
|
||||
|
||||
NCBusyIndicator {
|
||||
anchors.fill: parent
|
||||
visible: root.isSharePermissionChangeInProgress
|
||||
running: visible
|
||||
z: 1
|
||||
}
|
||||
}
|
||||
|
||||
NCRadioButton {
|
||||
readonly property int permissionMode: ShareModel.ModeFileDropOnly
|
||||
Layout.fillWidth: true
|
||||
ButtonGroup.group: permissionModeRadioButtonsGroup
|
||||
enabled: !root.isSharePermissionChangeInProgress
|
||||
checked: root.currentPermissionMode === permissionMode
|
||||
text: qsTr("File drop (upload only)")
|
||||
indicatorItemWidth: moreMenu.indicatorItemWidth
|
||||
indicatorItemHeight: moreMenu.indicatorItemWidth
|
||||
spacing: moreMenu.indicatorSpacing
|
||||
padding: moreMenu.itemPadding
|
||||
onClicked: root.permissionModeChanged(permissionMode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
Layout.fillWidth: true
|
||||
|
||||
spacing: moreMenu.indicatorSpacing
|
||||
padding: moreMenu.itemPadding
|
||||
indicator.width: moreMenu.indicatorItemWidth
|
||||
indicator.height: moreMenu.indicatorItemWidth
|
||||
active: root.isLinkShare
|
||||
visible: active
|
||||
sourceComponent: ColumnLayout {
|
||||
CheckBox {
|
||||
id: hideDownloadEnabledMenuItem
|
||||
|
||||
checkable: true
|
||||
checked: root.editingAllowed
|
||||
text: qsTr("Allow editing")
|
||||
enabled: !root.waitingForEditingAllowedChange
|
||||
visible: !root.isSecureFileDropLink
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
onClicked: {
|
||||
root.toggleAllowEditing(checked);
|
||||
root.waitingForEditingAllowedChange = true;
|
||||
}
|
||||
spacing: moreMenu.indicatorSpacing
|
||||
padding: moreMenu.itemPadding
|
||||
indicator.width: moreMenu.indicatorItemWidth
|
||||
indicator.height: moreMenu.indicatorItemWidth
|
||||
checked: root.hideDownload
|
||||
text: qsTr("Hide download")
|
||||
enabled: !root.isHideDownloadInProgress
|
||||
onClicked: root.toggleHideDownload(checked);
|
||||
|
||||
NCBusyIndicator {
|
||||
anchors.fill: parent
|
||||
visible: root.waitingForEditingAllowedChange
|
||||
running: visible
|
||||
z: 1
|
||||
NCBusyIndicator {
|
||||
anchors.fill: parent
|
||||
visible: root.isHideDownloadInProgress
|
||||
running: visible
|
||||
z: 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -241,9 +241,11 @@ ColumnLayout {
|
|||
|
||||
onToggleAllowEditing: shareModel.toggleShareAllowEditingFromQml(model.share, enable)
|
||||
onToggleAllowResharing: shareModel.toggleShareAllowResharingFromQml(model.share, enable)
|
||||
onToggleHideDownload: shareModel.toggleHideDownloadFromQml(model.share, enable)
|
||||
onTogglePasswordProtect: shareModel.toggleSharePasswordProtectFromQml(model.share, enable)
|
||||
onToggleExpirationDate: shareModel.toggleShareExpirationDateFromQml(model.share, enable)
|
||||
onToggleNoteToRecipient: shareModel.toggleShareNoteToRecipientFromQml(model.share, enable)
|
||||
onPermissionModeChanged: shareModel.changePermissionModeFromQml(model.share, permissionMode)
|
||||
|
||||
onSetLinkShareLabel: shareModel.setLinkShareLabelFromQml(model.share, label)
|
||||
onSetExpireDate: shareModel.setShareExpireDateFromQml(model.share, milliseconds)
|
||||
|
|
|
@ -81,7 +81,11 @@ QHash<int, QByteArray> ShareModel::roleNames() const
|
|||
roles[PasswordRole] = "password";
|
||||
roles[PasswordEnforcedRole] = "passwordEnforced";
|
||||
roles[EditingAllowedRole] = "editingAllowed";
|
||||
roles[IsSecureFileDropLinkRole] = "isSecureFileDropLink";
|
||||
roles[CurrentPermissionModeRole] = "currentPermissionMode";
|
||||
roles[SharedItemTypeRole] = "sharedItemType";
|
||||
roles[IsSharePermissionsChangeInProgress] = "isSharePermissionChangeInProgress";
|
||||
roles[HideDownloadEnabledRole] = "hideDownload";
|
||||
roles[IsHideDownloadEnabledChangeInProgress] = "isHideDownloadInProgress";
|
||||
|
||||
return roles;
|
||||
}
|
||||
|
@ -107,6 +111,8 @@ QVariant ShareModel::data(const QModelIndex &index, const int role) const
|
|||
return linkShare->getLabel();
|
||||
case NoteEnabledRole:
|
||||
return !linkShare->getNote().isEmpty();
|
||||
case HideDownloadEnabledRole:
|
||||
return linkShare->getHideDownload();
|
||||
case NoteRole:
|
||||
return linkShare->getNote();
|
||||
case ExpireDateEnabledRole:
|
||||
|
@ -151,8 +157,22 @@ QVariant ShareModel::data(const QModelIndex &index, const int role) const
|
|||
return expireDateEnforcedForShare(share);
|
||||
case EnforcedMaximumExpireDateRole:
|
||||
return enforcedMaxExpireDateForShare(share);
|
||||
case IsSecureFileDropLinkRole:
|
||||
return _isSecureFileDropSupportedFolder && share->getPermissions().testFlag(OCC::SharePermission::SharePermissionCreate);
|
||||
case CurrentPermissionModeRole: {
|
||||
if (share->getPermissions() == OCC::SharePermission::SharePermissionCreate) {
|
||||
return QVariant::fromValue(SharePermissionsMode::ModeFileDropOnly);
|
||||
} else if ((share->getPermissions() & SharePermissionRead) && (share->getPermissions() & SharePermissionCreate)
|
||||
&& (share->getPermissions() & SharePermissionUpdate) && (share->getPermissions() & SharePermissionDelete)) {
|
||||
return QVariant::fromValue(SharePermissionsMode::ModeUploadAndEditing);
|
||||
} else {
|
||||
return QVariant::fromValue(SharePermissionsMode::ModeViewOnly);
|
||||
}
|
||||
}
|
||||
case SharedItemTypeRole:
|
||||
return static_cast<int>(_sharedItemType);
|
||||
case IsSharePermissionsChangeInProgress:
|
||||
return _sharePermissionsChangeInProgress;
|
||||
case IsHideDownloadEnabledChangeInProgress:
|
||||
return _hideDownloadEnabledChangeInProgress;
|
||||
case PasswordProtectEnabledRole:
|
||||
return share->isPasswordSet();
|
||||
case PasswordRole:
|
||||
|
@ -250,9 +270,15 @@ void ShareModel::updateData()
|
|||
|
||||
_numericFileId = fileRecord.numericFileId();
|
||||
|
||||
_isEncryptedItem = fileRecord.isE2eEncrypted();
|
||||
_isSecureFileDropSupportedFolder =
|
||||
fileRecord.isE2eEncrypted() && fileRecord.e2eMangledName().isEmpty() && _accountState->account()->secureFileDropSupported();
|
||||
if (fileRecord.isDirectory()) {
|
||||
if (fileRecord.isE2eEncrypted()) {
|
||||
_sharedItemType = fileRecord.e2eMangledName().isEmpty() ? SharedItemType::SharedItemTypeEncryptedTopLevelFolder : SharedItemType::SharedItemTypeEncryptedFolder;
|
||||
} else {
|
||||
_sharedItemType = SharedItemType::SharedItemTypeFolder;
|
||||
}
|
||||
} else {
|
||||
_sharedItemType = fileRecord.isE2eEncrypted() ? SharedItemType::SharedItemTypeEncryptedFile : SharedItemType::SharedItemTypeFile;
|
||||
}
|
||||
|
||||
// Will get added when shares are fetched if no link shares are fetched
|
||||
_placeholderLinkShare.reset(new Share(_accountState->account(),
|
||||
|
@ -386,9 +412,9 @@ void ShareModel::handleSecureFileDropLinkShare()
|
|||
|
||||
void ShareModel::handleLinkShare()
|
||||
{
|
||||
if (!_isEncryptedItem) {
|
||||
if (!isEncryptedItem()) {
|
||||
handlePlaceholderLinkShare();
|
||||
} else if (_isSecureFileDropSupportedFolder) {
|
||||
} else if (isSecureFileDropSupportedFolder()) {
|
||||
handleSecureFileDropLinkShare();
|
||||
}
|
||||
}
|
||||
|
@ -456,7 +482,7 @@ void ShareModel::setupInternalLinkShare()
|
|||
_accountState->account().isNull() ||
|
||||
_localPath.isEmpty() ||
|
||||
_privateLinkUrl.isEmpty() ||
|
||||
_isEncryptedItem) {
|
||||
isEncryptedItem()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -466,6 +492,30 @@ void ShareModel::setupInternalLinkShare()
|
|||
Q_EMIT internalLinkReady();
|
||||
}
|
||||
|
||||
void ShareModel::setSharePermissionChangeInProgress(const QString &shareId, const bool isInProgress)
|
||||
{
|
||||
if (isInProgress == _sharePermissionsChangeInProgress) {
|
||||
return;
|
||||
}
|
||||
|
||||
_sharePermissionsChangeInProgress = isInProgress;
|
||||
|
||||
const auto shareIndex = _shareIdIndexHash.value(shareId);
|
||||
Q_EMIT dataChanged(shareIndex, shareIndex, {IsSharePermissionsChangeInProgress});
|
||||
}
|
||||
|
||||
void ShareModel::setHideDownloadEnabledChangeInProgress(const QString &shareId, const bool isInProgress)
|
||||
{
|
||||
if (isInProgress == _hideDownloadEnabledChangeInProgress) {
|
||||
return;
|
||||
}
|
||||
|
||||
_hideDownloadEnabledChangeInProgress = isInProgress;
|
||||
|
||||
const auto shareIndex = _shareIdIndexHash.value(shareId);
|
||||
Q_EMIT dataChanged(shareIndex, shareIndex, {IsHideDownloadEnabledChangeInProgress});
|
||||
}
|
||||
|
||||
void ShareModel::slotAddShare(const SharePtr &share)
|
||||
{
|
||||
if (share.isNull()) {
|
||||
|
@ -515,6 +565,7 @@ void ShareModel::slotAddShare(const SharePtr &share)
|
|||
connect(linkShare.data(), &LinkShare::nameSet, this, [this, shareId]{ slotShareNameSet(shareId); });
|
||||
connect(linkShare.data(), &LinkShare::labelSet, this, [this, shareId]{ slotShareLabelSet(shareId); });
|
||||
connect(linkShare.data(), &LinkShare::expireDateSet, this, [this, shareId]{ slotShareExpireDateSet(shareId); });
|
||||
connect(linkShare.data(), &LinkShare::hideDownloadSet, this, [this, shareId] { slotHideDownloadSet(shareId); });
|
||||
} else if (const auto userGroupShare = share.objectCast<UserGroupShare>()) {
|
||||
connect(userGroupShare.data(), &UserGroupShare::noteSet, this, [this, shareId]{ slotShareNoteSet(shareId); });
|
||||
connect(userGroupShare.data(), &UserGroupShare::expireDateSet, this, [this, shareId]{ slotShareExpireDateSet(shareId); });
|
||||
|
@ -582,7 +633,7 @@ QString ShareModel::displayStringForShare(const SharePtr &share) const
|
|||
{
|
||||
if (const auto linkShare = share.objectCast<LinkShare>()) {
|
||||
|
||||
const auto isSecureFileDropShare = _isSecureFileDropSupportedFolder && linkShare->getPermissions().testFlag(OCC::SharePermission::SharePermissionCreate);
|
||||
const auto isSecureFileDropShare = isSecureFileDropSupportedFolder() && linkShare->getPermissions().testFlag(OCC::SharePermission::SharePermissionCreate);
|
||||
|
||||
const auto displayString = isSecureFileDropShare ? tr("Secure file drop link") : tr("Share link");
|
||||
|
||||
|
@ -708,7 +759,8 @@ void ShareModel::slotSharePermissionsSet(const QString &shareId)
|
|||
|
||||
const auto sharePersistentModelIndex = _shareIdIndexHash.value(shareId);
|
||||
const auto shareModelIndex = index(sharePersistentModelIndex.row());
|
||||
Q_EMIT dataChanged(shareModelIndex, shareModelIndex, { EditingAllowedRole });
|
||||
Q_EMIT dataChanged(shareModelIndex, shareModelIndex, { EditingAllowedRole, CurrentPermissionModeRole });
|
||||
setSharePermissionChangeInProgress(shareId, false);
|
||||
}
|
||||
|
||||
void ShareModel::slotSharePasswordSet(const QString &shareId)
|
||||
|
@ -722,6 +774,18 @@ void ShareModel::slotSharePasswordSet(const QString &shareId)
|
|||
Q_EMIT dataChanged(shareModelIndex, shareModelIndex, { PasswordProtectEnabledRole, PasswordRole });
|
||||
}
|
||||
|
||||
void ShareModel::slotHideDownloadSet(const QString &shareId)
|
||||
{
|
||||
if (shareId.isEmpty() || !_shareIdIndexHash.contains(shareId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto sharePersistentModelIndex = _shareIdIndexHash.value(shareId);
|
||||
const auto shareModelIndex = index(sharePersistentModelIndex.row());
|
||||
Q_EMIT dataChanged(shareModelIndex, shareModelIndex, {HideDownloadEnabledRole});
|
||||
setHideDownloadEnabledChangeInProgress(shareId, false);
|
||||
}
|
||||
|
||||
void ShareModel::slotShareNoteSet(const QString &shareId)
|
||||
{
|
||||
if (shareId.isEmpty() || !_shareIdIndexHash.contains(shareId)) {
|
||||
|
@ -768,37 +832,56 @@ void ShareModel::slotShareExpireDateSet(const QString &shareId)
|
|||
|
||||
// ----------------------- Shares modification slots ----------------------- //
|
||||
|
||||
void ShareModel::toggleShareAllowEditing(const SharePtr &share, const bool enable) const
|
||||
void ShareModel::toggleShareAllowEditing(const SharePtr &share, const bool enable)
|
||||
{
|
||||
if (share.isNull()) {
|
||||
if (share.isNull() || _sharePermissionsChangeInProgress) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto permissions = share->getPermissions();
|
||||
enable ? permissions |= SharePermissionUpdate : permissions &= ~SharePermissionUpdate;
|
||||
|
||||
setSharePermissionChangeInProgress(share->getId(), true);
|
||||
share->setPermissions(permissions);
|
||||
}
|
||||
|
||||
void ShareModel::toggleShareAllowEditingFromQml(const QVariant &share, const bool enable) const
|
||||
void ShareModel::toggleShareAllowEditingFromQml(const QVariant &share, const bool enable)
|
||||
{
|
||||
const auto ptr = share.value<SharePtr>();
|
||||
toggleShareAllowEditing(ptr, enable);
|
||||
}
|
||||
|
||||
void ShareModel::toggleShareAllowResharing(const SharePtr &share, const bool enable) const
|
||||
void ShareModel::toggleShareAllowResharing(const SharePtr &share, const bool enable)
|
||||
{
|
||||
if (share.isNull()) {
|
||||
if (share.isNull() || _sharePermissionsChangeInProgress) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto permissions = share->getPermissions();
|
||||
enable ? permissions |= SharePermissionShare : permissions &= ~SharePermissionShare;
|
||||
|
||||
setSharePermissionChangeInProgress(share->getId(), true);
|
||||
share->setPermissions(permissions);
|
||||
}
|
||||
|
||||
void ShareModel::toggleShareAllowResharingFromQml(const QVariant &share, const bool enable) const
|
||||
void ShareModel::toggleHideDownloadFromQml(const QVariant &share, const bool enable)
|
||||
{
|
||||
const auto sharePtr = share.value<SharePtr>();
|
||||
if (sharePtr.isNull() || _hideDownloadEnabledChangeInProgress) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto linkShare = sharePtr.objectCast<LinkShare>();
|
||||
|
||||
if (linkShare.isNull()) {
|
||||
return;
|
||||
}
|
||||
|
||||
setHideDownloadEnabledChangeInProgress(linkShare->getId(), true);
|
||||
linkShare->setHideDownload(enable);
|
||||
}
|
||||
|
||||
void ShareModel::toggleShareAllowResharingFromQml(const QVariant &share, const bool enable)
|
||||
{
|
||||
const auto ptr = share.value<SharePtr>();
|
||||
toggleShareAllowResharing(ptr, enable);
|
||||
|
@ -867,6 +950,42 @@ void ShareModel::toggleShareNoteToRecipientFromQml(const QVariant &share, const
|
|||
toggleShareNoteToRecipient(ptr, enable);
|
||||
}
|
||||
|
||||
void ShareModel::changePermissionModeFromQml(const QVariant &share, const SharePermissionsMode permissionMode)
|
||||
{
|
||||
const auto sharePtr = share.value<SharePtr>();
|
||||
if (sharePtr.isNull() || _sharePermissionsChangeInProgress) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto shareIndex = _shareIdIndexHash.value(sharePtr->getId());
|
||||
|
||||
if (!checkIndex(shareIndex, QAbstractItemModel::CheckIndexOption::IndexIsValid | QAbstractItemModel::CheckIndexOption::ParentIsInvalid)) {
|
||||
qCWarning(lcShareModel) << "Can't change permission mode for:" << sharePtr->getId() << ", invalid share index: " << shareIndex;
|
||||
return;
|
||||
}
|
||||
|
||||
const auto currentPermissionMode = shareIndex.data(ShareModel::CurrentPermissionModeRole).value<SharePermissionsMode>();
|
||||
|
||||
if (currentPermissionMode == permissionMode) {
|
||||
return;
|
||||
}
|
||||
|
||||
SharePermissions perm = SharePermissionRead;
|
||||
switch (permissionMode) {
|
||||
case SharePermissionsMode::ModeViewOnly:
|
||||
break;
|
||||
case SharePermissionsMode::ModeUploadAndEditing:
|
||||
perm |= SharePermissionCreate | SharePermissionUpdate | SharePermissionDelete;
|
||||
break;
|
||||
case SharePermissionsMode::ModeFileDropOnly:
|
||||
perm = SharePermissionCreate;
|
||||
break;
|
||||
}
|
||||
|
||||
setSharePermissionChangeInProgress(sharePtr->getId(), true);
|
||||
sharePtr->setPermissions(perm);
|
||||
}
|
||||
|
||||
void ShareModel::setLinkShareLabel(const QSharedPointer<LinkShare> &linkShare, const QString &label) const
|
||||
{
|
||||
if (linkShare.isNull()) {
|
||||
|
@ -944,7 +1063,7 @@ void ShareModel::setShareNoteFromQml(const QVariant &share, const QString ¬e)
|
|||
|
||||
void ShareModel::createNewLinkShare() const
|
||||
{
|
||||
if (_isEncryptedItem && !_isSecureFileDropSupportedFolder) {
|
||||
if (isEncryptedItem() && !isSecureFileDropSupportedFolder()) {
|
||||
qCWarning(lcShareModel) << "Attempt to create a link share for non-root encrypted folder or a file.";
|
||||
return;
|
||||
}
|
||||
|
@ -952,7 +1071,7 @@ void ShareModel::createNewLinkShare() const
|
|||
if (_manager) {
|
||||
const auto askOptionalPassword = _accountState->account()->capabilities().sharePublicLinkAskOptionalPassword();
|
||||
const auto password = askOptionalPassword ? createRandomPassword() : QString();
|
||||
if (_isSecureFileDropSupportedFolder) {
|
||||
if (isSecureFileDropSupportedFolder()) {
|
||||
_manager->createSecureFileDropShare(_sharePath, {}, password);
|
||||
return;
|
||||
}
|
||||
|
@ -1089,6 +1208,17 @@ bool ShareModel::validCapabilities() const
|
|||
_accountState->account()->capabilities().isValid();
|
||||
}
|
||||
|
||||
bool ShareModel::isSecureFileDropSupportedFolder() const
|
||||
{
|
||||
return _sharedItemType == SharedItemType::SharedItemTypeEncryptedTopLevelFolder && _accountState->account()->secureFileDropSupported();
|
||||
}
|
||||
|
||||
bool ShareModel::isEncryptedItem() const
|
||||
{
|
||||
return _sharedItemType == SharedItemType::SharedItemTypeEncryptedFile || _sharedItemType == SharedItemType::SharedItemTypeEncryptedFolder
|
||||
|| _sharedItemType == SharedItemType::SharedItemTypeEncryptedTopLevelFolder;
|
||||
}
|
||||
|
||||
bool ShareModel::sharingEnabled() const
|
||||
{
|
||||
return validCapabilities() &&
|
||||
|
|
|
@ -57,7 +57,11 @@ public:
|
|||
PasswordRole,
|
||||
PasswordEnforcedRole,
|
||||
EditingAllowedRole,
|
||||
IsSecureFileDropLinkRole,
|
||||
CurrentPermissionModeRole,
|
||||
SharedItemTypeRole,
|
||||
IsSharePermissionsChangeInProgress,
|
||||
HideDownloadEnabledRole,
|
||||
IsHideDownloadEnabledChangeInProgress,
|
||||
};
|
||||
Q_ENUM(Roles)
|
||||
|
||||
|
@ -79,6 +83,23 @@ public:
|
|||
ShareTypeSecureFileDropPlaceholderLink = Share::TypeSecureFileDropPlaceholderLink,
|
||||
};
|
||||
Q_ENUM(ShareType);
|
||||
|
||||
enum class SharedItemType {
|
||||
SharedItemTypeUndefined = -1,
|
||||
SharedItemTypeFile,
|
||||
SharedItemTypeFolder,
|
||||
SharedItemTypeEncryptedFile,
|
||||
SharedItemTypeEncryptedFolder,
|
||||
SharedItemTypeEncryptedTopLevelFolder,
|
||||
};
|
||||
Q_ENUM(SharedItemType);
|
||||
|
||||
enum class SharePermissionsMode {
|
||||
ModeViewOnly,
|
||||
ModeUploadAndEditing,
|
||||
ModeFileDropOnly,
|
||||
};
|
||||
Q_ENUM(SharePermissionsMode);
|
||||
|
||||
explicit ShareModel(QObject *parent = nullptr);
|
||||
|
||||
|
@ -135,16 +156,18 @@ public slots:
|
|||
void deleteShare(const OCC::SharePtr &share) const;
|
||||
void deleteShareFromQml(const QVariant &share) const;
|
||||
|
||||
void toggleShareAllowEditing(const OCC::SharePtr &share, const bool enable) const;
|
||||
void toggleShareAllowEditingFromQml(const QVariant &share, const bool enable) const;
|
||||
void toggleShareAllowResharing(const OCC::SharePtr &share, const bool enable) const;
|
||||
void toggleShareAllowResharingFromQml(const QVariant &share, const bool enable) const;
|
||||
void toggleHideDownloadFromQml(const QVariant &share, const bool enable);
|
||||
void toggleShareAllowEditing(const OCC::SharePtr &share, const bool enable);
|
||||
void toggleShareAllowEditingFromQml(const QVariant &share, const bool enable);
|
||||
void toggleShareAllowResharing(const OCC::SharePtr &share, const bool enable);
|
||||
void toggleShareAllowResharingFromQml(const QVariant &share, const bool enable);
|
||||
void toggleSharePasswordProtect(const OCC::SharePtr &share, const bool enable);
|
||||
void toggleSharePasswordProtectFromQml(const QVariant &share, const bool enable);
|
||||
void toggleShareExpirationDate(const OCC::SharePtr &share, const bool enable) const;
|
||||
void toggleShareExpirationDateFromQml(const QVariant &share, const bool enable) const;
|
||||
void toggleShareNoteToRecipient(const OCC::SharePtr &share, const bool enable) const;
|
||||
void toggleShareNoteToRecipientFromQml(const QVariant &share, const bool enable) const;
|
||||
void changePermissionModeFromQml(const QVariant &share, const SharePermissionsMode permissionMode);
|
||||
|
||||
void setLinkShareLabel(const QSharedPointer<OCC::LinkShare> &linkShare, const QString &label) const;
|
||||
void setLinkShareLabelFromQml(const QVariant &linkShare, const QString &label) const;
|
||||
|
@ -164,6 +187,8 @@ private slots:
|
|||
void handleSecureFileDropLinkShare();
|
||||
void handleLinkShare();
|
||||
void setupInternalLinkShare();
|
||||
void setSharePermissionChangeInProgress(const QString &shareId, const bool isInProgress);
|
||||
void setHideDownloadEnabledChangeInProgress(const QString &shareId, const bool isInProgress);
|
||||
|
||||
void slotPropfindReceived(const QVariantMap &result);
|
||||
void slotServerError(const int code, const QString &message);
|
||||
|
@ -176,6 +201,7 @@ private slots:
|
|||
void slotSharePermissionsSet(const QString &shareId);
|
||||
void slotSharePasswordSet(const QString &shareId);
|
||||
void slotShareNoteSet(const QString &shareId);
|
||||
void slotHideDownloadSet(const QString &shareId);
|
||||
void slotShareNameSet(const QString &shareId);
|
||||
void slotShareLabelSet(const QString &shareId);
|
||||
void slotShareExpireDateSet(const QString &shareId);
|
||||
|
@ -187,9 +213,13 @@ private:
|
|||
[[nodiscard]] long long enforcedMaxExpireDateForShare(const SharePtr &share) const;
|
||||
[[nodiscard]] bool expireDateEnforcedForShare(const SharePtr &share) const;
|
||||
[[nodiscard]] bool validCapabilities() const;
|
||||
[[nodiscard]] bool isSecureFileDropSupportedFolder() const;
|
||||
[[nodiscard]] bool isEncryptedItem() const;
|
||||
|
||||
bool _fetchOngoing = false;
|
||||
bool _hasInitialShareFetchCompleted = false;
|
||||
bool _sharePermissionsChangeInProgress = false;
|
||||
bool _hideDownloadEnabledChangeInProgress = false;
|
||||
SharePtr _placeholderLinkShare;
|
||||
SharePtr _internalLinkShare;
|
||||
SharePtr _secureFileDropPlaceholderLinkShare;
|
||||
|
@ -201,8 +231,7 @@ private:
|
|||
QString _sharePath;
|
||||
SharePermissions _maxSharingPermissions;
|
||||
QByteArray _numericFileId;
|
||||
bool _isEncryptedItem = false;
|
||||
bool _isSecureFileDropSupportedFolder = false;
|
||||
SharedItemType _sharedItemType = SharedItemType::SharedItemTypeUndefined;
|
||||
SyncJournalFileLockInfo _filelockState;
|
||||
QString _privateLinkUrl;
|
||||
|
||||
|
|
|
@ -134,6 +134,18 @@ void OcsShareJob::setLabel(const QString &shareId, const QString &label)
|
|||
start();
|
||||
}
|
||||
|
||||
void OcsShareJob::setHideDownload(const QString &shareId, const bool hideDownload)
|
||||
{
|
||||
appendPath(shareId);
|
||||
setVerb("PUT");
|
||||
|
||||
const auto value = QString::fromLatin1(hideDownload ? QByteArrayLiteral("true") : QByteArrayLiteral("false"));
|
||||
addParam(QStringLiteral("hideDownload"), value);
|
||||
_value = hideDownload;
|
||||
|
||||
start();
|
||||
}
|
||||
|
||||
void OcsShareJob::createLinkShare(const QString &path,
|
||||
const QString &name,
|
||||
const QString &password)
|
||||
|
|
|
@ -102,6 +102,11 @@ public:
|
|||
*/
|
||||
void setLabel(const QString &shareId, const QString &label);
|
||||
|
||||
/**
|
||||
* Set share hideDownload flag
|
||||
*/
|
||||
void setHideDownload(const QString &shareId, const bool hideDownload);
|
||||
|
||||
/**
|
||||
* Create a new link share
|
||||
*
|
||||
|
|
|
@ -203,7 +203,8 @@ LinkShare::LinkShare(AccountPtr account,
|
|||
const QUrl &url,
|
||||
const QDate &expireDate,
|
||||
const QString ¬e,
|
||||
const QString &label)
|
||||
const QString &label,
|
||||
const bool hideDownload)
|
||||
: Share(account, id, uidowner, ownerDisplayName, path, Share::TypeLink, isPasswordSet, permissions)
|
||||
, _name(name)
|
||||
, _token(token)
|
||||
|
@ -211,6 +212,7 @@ LinkShare::LinkShare(AccountPtr account,
|
|||
, _expireDate(expireDate)
|
||||
, _url(url)
|
||||
, _label(label)
|
||||
, _hideDownload(hideDownload)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -239,6 +241,11 @@ QString LinkShare::getLabel() const
|
|||
return _label;
|
||||
}
|
||||
|
||||
bool LinkShare::getHideDownload() const
|
||||
{
|
||||
return _hideDownload;
|
||||
}
|
||||
|
||||
void LinkShare::setName(const QString &name)
|
||||
{
|
||||
createShareJob(&LinkShare::slotNameSet)->setName(getId(), name);
|
||||
|
@ -270,6 +277,11 @@ void LinkShare::setLabel(const QString &label)
|
|||
createShareJob(&LinkShare::slotLabelSet)->setLabel(getId(), label);
|
||||
}
|
||||
|
||||
void LinkShare::setHideDownload(const bool hideDownload)
|
||||
{
|
||||
createShareJob(&LinkShare::slotHideDownloadSet)->setHideDownload(getId(), hideDownload);
|
||||
}
|
||||
|
||||
template <typename LinkShareSlot>
|
||||
OcsShareJob *LinkShare::createShareJob(const LinkShareSlot slotFunction) {
|
||||
auto *job = new OcsShareJob(_account);
|
||||
|
@ -308,6 +320,16 @@ void LinkShare::slotLabelSet(const QJsonDocument &, const QVariant &label)
|
|||
}
|
||||
}
|
||||
|
||||
void LinkShare::slotHideDownloadSet(const QJsonDocument &jsonDoc, const QVariant &hideDownload)
|
||||
{
|
||||
Q_UNUSED(jsonDoc);
|
||||
if (!hideDownload.isValid()) {
|
||||
return;
|
||||
}
|
||||
_hideDownload = hideDownload.toBool();
|
||||
emit hideDownloadSet();
|
||||
}
|
||||
|
||||
UserGroupShare::UserGroupShare(AccountPtr account,
|
||||
const QString &id,
|
||||
const QString &owner,
|
||||
|
@ -583,7 +605,8 @@ QSharedPointer<LinkShare> ShareManager::parseLinkShare(const QJsonObject &data)
|
|||
url,
|
||||
expireDate,
|
||||
note,
|
||||
data.value("label").toString()));
|
||||
data.value("label").toString(),
|
||||
data.value("hide_download").toInt() == 1));
|
||||
}
|
||||
|
||||
SharePtr ShareManager::parseShare(const QJsonObject &data) const
|
||||
|
|
|
@ -132,6 +132,7 @@ signals:
|
|||
void shareDeleted();
|
||||
void serverError(int code, const QString &message);
|
||||
void passwordSet();
|
||||
void hideDownloadSet();
|
||||
void passwordSetError(int statusCode, const QString &message);
|
||||
|
||||
public slots:
|
||||
|
@ -197,6 +198,7 @@ class LinkShare : public Share
|
|||
Q_PROPERTY(QString name READ getName WRITE setName NOTIFY nameSet)
|
||||
Q_PROPERTY(QString note READ getNote WRITE setNote NOTIFY noteSet)
|
||||
Q_PROPERTY(QString label READ getLabel WRITE setLabel NOTIFY labelSet)
|
||||
Q_PROPERTY(bool hideDownload READ getHideDownload WRITE setHideDownload NOTIFY hideDownloadSet)
|
||||
Q_PROPERTY(QDate expireDate READ getExpireDate WRITE setExpireDate NOTIFY expireDateSet)
|
||||
Q_PROPERTY(QString token READ getToken CONSTANT)
|
||||
|
||||
|
@ -213,7 +215,8 @@ public:
|
|||
const QUrl &url,
|
||||
const QDate &expireDate,
|
||||
const QString ¬e,
|
||||
const QString &label);
|
||||
const QString &label,
|
||||
const bool hideDownload);
|
||||
|
||||
/*
|
||||
* Get the share link
|
||||
|
@ -250,6 +253,11 @@ public:
|
|||
*/
|
||||
[[nodiscard]] QString getLabel() const;
|
||||
|
||||
/*
|
||||
* Returns if the link share's hideDownload is true or false
|
||||
*/
|
||||
[[nodiscard]] bool getHideDownload() const;
|
||||
|
||||
/*
|
||||
* Returns the token of the link share.
|
||||
*/
|
||||
|
@ -291,18 +299,25 @@ public slots:
|
|||
* Set the label of the share link.
|
||||
*/
|
||||
void setLabel(const QString &label);
|
||||
|
||||
/*
|
||||
* Set the hideDownload flag of the share link.
|
||||
*/
|
||||
void setHideDownload(const bool hideDownload);
|
||||
|
||||
signals:
|
||||
void expireDateSet();
|
||||
void noteSet();
|
||||
void nameSet();
|
||||
void labelSet();
|
||||
void hideDownloadSet();
|
||||
|
||||
private slots:
|
||||
void slotNoteSet(const QJsonDocument &, const QVariant &value);
|
||||
void slotExpireDateSet(const QJsonDocument &reply, const QVariant &value);
|
||||
void slotNameSet(const QJsonDocument &, const QVariant &value);
|
||||
void slotLabelSet(const QJsonDocument &, const QVariant &value);
|
||||
void slotHideDownloadSet(const QJsonDocument &jsonDoc, const QVariant &hideDownload);
|
||||
|
||||
private:
|
||||
QString _name;
|
||||
|
@ -311,6 +326,7 @@ private:
|
|||
QDate _expireDate;
|
||||
QUrl _url;
|
||||
QString _label;
|
||||
bool _hideDownload = false;
|
||||
};
|
||||
|
||||
class UserGroupShare : public Share
|
||||
|
|
|
@ -122,6 +122,11 @@ QtObject {
|
|||
readonly property int unifiedSearchResultSectionItemVerticalPadding: 8
|
||||
readonly property int unifiedSearchResultNothingFoundHorizontalMargin: 10
|
||||
|
||||
readonly property int radioButtonCustomMarginLeftInner: 4
|
||||
readonly property int radioButtonCustomMarginLeftOuter: 5
|
||||
readonly property int radioButtonCustomRadius: 9
|
||||
readonly property int radioButtonIndicatorSize: 16
|
||||
|
||||
readonly property var fontMetrics: FontMetrics {}
|
||||
|
||||
readonly property int activityContentSpace: 4
|
||||
|
|
Loading…
Reference in a new issue