Просмотр исходного кода

Merge pull request #5622 from nextcloud/feature/bring-back-missing-share-options

Implement missing share settings
allexzander 2 лет назад
Родитель
Сommit
6eb248b37f

+ 1 - 0
resources.qrc

@@ -51,5 +51,6 @@
         <file>src/gui/tray/EnforcedPlainTextLabel.qml</file>
         <file>src/gui/tray/EnforcedPlainTextLabel.qml</file>
         <file>theme/Style/Style.qml</file>
         <file>theme/Style/Style.qml</file>
         <file>theme/Style/qmldir</file>
         <file>theme/Style/qmldir</file>
+        <file>src/gui/filedetails/NCRadioButton.qml</file>
     </qresource>
     </qresource>
 </RCC>
 </RCC>

+ 43 - 0
src/gui/filedetails/NCRadioButton.qml

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

+ 4 - 0
src/gui/filedetails/ShareDelegate.qml

@@ -33,11 +33,13 @@ GridLayout {
     signal resetPasswordField
     signal resetPasswordField
     signal showPasswordSetError(string errorMessage);
     signal showPasswordSetError(string errorMessage);
 
 
+    signal toggleHideDownload(bool enable)
     signal toggleAllowEditing(bool enable)
     signal toggleAllowEditing(bool enable)
     signal toggleAllowResharing(bool enable)
     signal toggleAllowResharing(bool enable)
     signal togglePasswordProtect(bool enable)
     signal togglePasswordProtect(bool enable)
     signal toggleExpirationDate(bool enable)
     signal toggleExpirationDate(bool enable)
     signal toggleNoteToRecipient(bool enable)
     signal toggleNoteToRecipient(bool enable)
+    signal permissionModeChanged(int permissionMode)
 
 
     signal setLinkShareLabel(string label)
     signal setLinkShareLabel(string label)
     signal setExpireDate(var milliseconds) // Since QML ints are only 32 bits, use a variant
     signal setExpireDate(var milliseconds) // Since QML ints are only 32 bits, use a variant
@@ -236,9 +238,11 @@ GridLayout {
 
 
                     onToggleAllowEditing: root.toggleAllowEditing(enable)
                     onToggleAllowEditing: root.toggleAllowEditing(enable)
                     onToggleAllowResharing: root.toggleAllowResharing(enable)
                     onToggleAllowResharing: root.toggleAllowResharing(enable)
+                    onToggleHideDownload: root.toggleHideDownload(enable)
                     onTogglePasswordProtect: root.togglePasswordProtect(enable)
                     onTogglePasswordProtect: root.togglePasswordProtect(enable)
                     onToggleExpirationDate: root.toggleExpirationDate(enable)
                     onToggleExpirationDate: root.toggleExpirationDate(enable)
                     onToggleNoteToRecipient: root.toggleNoteToRecipient(enable)
                     onToggleNoteToRecipient: root.toggleNoteToRecipient(enable)
+                    onPermissionModeChanged: root.permissionModeChanged(permissionMode)
 
 
                     onSetLinkShareLabel: root.setLinkShareLabel(label)
                     onSetLinkShareLabel: root.setLinkShareLabel(label)
                     onSetExpireDate: root.setExpireDate(milliseconds) // Since QML ints are only 32 bits, use a variant
                     onSetExpireDate: root.setExpireDate(milliseconds) // Since QML ints are only 32 bits, use a variant

+ 120 - 32
src/gui/filedetails/ShareDetailsPage.qml

@@ -32,9 +32,11 @@ Page {
 
 
     signal toggleAllowEditing(bool enable)
     signal toggleAllowEditing(bool enable)
     signal toggleAllowResharing(bool enable)
     signal toggleAllowResharing(bool enable)
+    signal toggleHideDownload(bool enable)
     signal togglePasswordProtect(bool enable)
     signal togglePasswordProtect(bool enable)
     signal toggleExpirationDate(bool enable)
     signal toggleExpirationDate(bool enable)
     signal toggleNoteToRecipient(bool enable)
     signal toggleNoteToRecipient(bool enable)
+    signal permissionModeChanged(int permissionMode)
 
 
     signal setLinkShareLabel(string label)
     signal setLinkShareLabel(string label)
     signal setExpireDate(var milliseconds) // Since QML ints are only 32 bits, use a variant
     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 string linkShareLabel: shareModelData.linkShareLabel ?? ""
 
 
     readonly property bool editingAllowed: shareModelData.editingAllowed
     readonly property bool editingAllowed: shareModelData.editingAllowed
+    readonly property bool hideDownload: shareModelData.hideDownload
     readonly property bool noteEnabled: shareModelData.noteEnabled
     readonly property bool noteEnabled: shareModelData.noteEnabled
     readonly property bool expireDateEnabled: shareModelData.expireDateEnabled
     readonly property bool expireDateEnabled: shareModelData.expireDateEnabled
     readonly property bool expireDateEnforced: shareModelData.expireDateEnforced
     readonly property bool expireDateEnforced: shareModelData.expireDateEnforced
     readonly property bool passwordProtectEnabled: shareModelData.passwordProtectEnabled
     readonly property bool passwordProtectEnabled: shareModelData.passwordProtectEnabled
     readonly property bool passwordEnforced: shareModelData.passwordEnforced
     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
     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 waitingForNoteEnabledChange: false
     property bool waitingForExpireDateEnabledChange: false
     property bool waitingForExpireDateEnabledChange: false
     property bool waitingForPasswordProtectEnabledChange: false
     property bool waitingForPasswordProtectEnabledChange: false
@@ -108,11 +115,6 @@ Page {
         waitingForExpireDateChange = false;
         waitingForExpireDateChange = false;
     }
     }
 
 
-    function resetEditingAllowedField() {
-        editingAllowedMenuItem.checked = editingAllowed;
-        waitingForEditingAllowedChange = false;
-    }
-
     function resetNoteEnabledField() {
     function resetNoteEnabledField() {
         noteEnabledMenuItem.checked = noteEnabled;
         noteEnabledMenuItem.checked = noteEnabled;
         waitingForNoteEnabledChange = false;
         waitingForNoteEnabledChange = false;
@@ -135,8 +137,6 @@ Page {
         resetPasswordField();
         resetPasswordField();
         resetLinkShareLabelField();
         resetLinkShareLabelField();
         resetExpireDateField();
         resetExpireDateField();
-
-        resetEditingAllowedField();
         resetNoteEnabledField();
         resetNoteEnabledField();
         resetExpireDateEnabledField();
         resetExpireDateEnabledField();
         resetPasswordProtectEnabledField();
         resetPasswordProtectEnabledField();
@@ -154,8 +154,6 @@ Page {
     onPasswordChanged: resetPasswordField()
     onPasswordChanged: resetPasswordField()
     onLinkShareLabelChanged: resetLinkShareLabelField()
     onLinkShareLabelChanged: resetLinkShareLabelField()
     onExpireDateChanged: resetExpireDateField()
     onExpireDateChanged: resetExpireDateField()
-
-    onEditingAllowedChanged: resetEditingAllowedField()
     onNoteEnabledChanged: resetNoteEnabledField()
     onNoteEnabledChanged: resetNoteEnabledField()
     onExpireDateEnabledChanged: resetExpireDateEnabledField()
     onExpireDateEnabledChanged: resetExpireDateEnabledField()
     onPasswordProtectEnabledChanged: resetPasswordProtectEnabledField()
     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
                 Layout.fillWidth: true
+                active: root.isFolderItem && !root.isEncryptedItem
+                visible: active
+                sourceComponent: ColumnLayout {
+                    id: permissionRadioButtonsLayout
+                    spacing: 0
+                    width: parent.width
 
 
-                spacing: moreMenu.indicatorSpacing
-                padding: moreMenu.itemPadding
-                indicator.width: moreMenu.indicatorItemWidth
-                indicator.height: moreMenu.indicatorItemWidth
+                    ButtonGroup {
+                        id: permissionModeRadioButtonsGroup
+                    }
 
 
-                checkable: true
-                checked: root.editingAllowed
-                text: qsTr("Allow editing")
-                enabled: !root.waitingForEditingAllowedChange
-                visible: !root.isSecureFileDropLink
+                    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)
+                    }
 
 
-                onClicked: {
-                    root.toggleAllowEditing(checked);
-                    root.waitingForEditingAllowedChange = true;
+                    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)
+                    }
                 }
                 }
+            }
 
 
-                NCBusyIndicator {
-                    anchors.fill: parent
-                    visible: root.waitingForEditingAllowedChange
-                    running: visible
-                    z: 1
+            Loader {
+                Layout.fillWidth: true
+
+                active: root.isLinkShare
+                visible: active
+                sourceComponent: ColumnLayout {
+                    CheckBox {
+                        id: hideDownloadEnabledMenuItem
+
+                        anchors.left: parent.left
+                        anchors.right: parent.right
+
+                        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.isHideDownloadInProgress
+                            running: visible
+                            z: 1
+                        }
+                    }
                 }
                 }
             }
             }
 
 

+ 2 - 0
src/gui/filedetails/ShareView.qml

@@ -241,9 +241,11 @@ ColumnLayout {
 
 
                     onToggleAllowEditing: shareModel.toggleShareAllowEditingFromQml(model.share, enable)
                     onToggleAllowEditing: shareModel.toggleShareAllowEditingFromQml(model.share, enable)
                     onToggleAllowResharing: shareModel.toggleShareAllowResharingFromQml(model.share, enable)
                     onToggleAllowResharing: shareModel.toggleShareAllowResharingFromQml(model.share, enable)
+                    onToggleHideDownload: shareModel.toggleHideDownloadFromQml(model.share, enable)
                     onTogglePasswordProtect: shareModel.toggleSharePasswordProtectFromQml(model.share, enable)
                     onTogglePasswordProtect: shareModel.toggleSharePasswordProtectFromQml(model.share, enable)
                     onToggleExpirationDate: shareModel.toggleShareExpirationDateFromQml(model.share, enable)
                     onToggleExpirationDate: shareModel.toggleShareExpirationDateFromQml(model.share, enable)
                     onToggleNoteToRecipient: shareModel.toggleShareNoteToRecipientFromQml(model.share, enable)
                     onToggleNoteToRecipient: shareModel.toggleShareNoteToRecipientFromQml(model.share, enable)
+                    onPermissionModeChanged: shareModel.changePermissionModeFromQml(model.share, permissionMode)
 
 
                     onSetLinkShareLabel: shareModel.setLinkShareLabelFromQml(model.share, label)
                     onSetLinkShareLabel: shareModel.setLinkShareLabelFromQml(model.share, label)
                     onSetExpireDate: shareModel.setShareExpireDateFromQml(model.share, milliseconds)
                     onSetExpireDate: shareModel.setShareExpireDateFromQml(model.share, milliseconds)

+ 149 - 19
src/gui/filedetails/sharemodel.cpp

@@ -81,7 +81,11 @@ QHash<int, QByteArray> ShareModel::roleNames() const
     roles[PasswordRole] = "password";
     roles[PasswordRole] = "password";
     roles[PasswordEnforcedRole] = "passwordEnforced";
     roles[PasswordEnforcedRole] = "passwordEnforced";
     roles[EditingAllowedRole] = "editingAllowed";
     roles[EditingAllowedRole] = "editingAllowed";
-    roles[IsSecureFileDropLinkRole] = "isSecureFileDropLink";
+    roles[CurrentPermissionModeRole] = "currentPermissionMode";
+    roles[SharedItemTypeRole] = "sharedItemType";
+    roles[IsSharePermissionsChangeInProgress] = "isSharePermissionChangeInProgress";
+    roles[HideDownloadEnabledRole] = "hideDownload";
+    roles[IsHideDownloadEnabledChangeInProgress] = "isHideDownloadInProgress";
 
 
     return roles;
     return roles;
 }
 }
@@ -107,6 +111,8 @@ QVariant ShareModel::data(const QModelIndex &index, const int role) const
             return linkShare->getLabel();
             return linkShare->getLabel();
         case NoteEnabledRole:
         case NoteEnabledRole:
             return !linkShare->getNote().isEmpty();
             return !linkShare->getNote().isEmpty();
+        case HideDownloadEnabledRole:
+            return linkShare->getHideDownload();
         case NoteRole:
         case NoteRole:
             return linkShare->getNote();
             return linkShare->getNote();
         case ExpireDateEnabledRole:
         case ExpireDateEnabledRole:
@@ -151,8 +157,22 @@ QVariant ShareModel::data(const QModelIndex &index, const int role) const
         return expireDateEnforcedForShare(share);
         return expireDateEnforcedForShare(share);
     case EnforcedMaximumExpireDateRole:
     case EnforcedMaximumExpireDateRole:
         return enforcedMaxExpireDateForShare(share);
         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:
     case PasswordProtectEnabledRole:
         return share->isPasswordSet();
         return share->isPasswordSet();
     case PasswordRole:
     case PasswordRole:
@@ -250,9 +270,15 @@ void ShareModel::updateData()
 
 
     _numericFileId = fileRecord.numericFileId();
     _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
     // Will get added when shares are fetched if no link shares are fetched
     _placeholderLinkShare.reset(new Share(_accountState->account(),
     _placeholderLinkShare.reset(new Share(_accountState->account(),
@@ -386,9 +412,9 @@ void ShareModel::handleSecureFileDropLinkShare()
 
 
 void ShareModel::handleLinkShare()
 void ShareModel::handleLinkShare()
 {
 {
-    if (!_isEncryptedItem) {
+    if (!isEncryptedItem()) {
         handlePlaceholderLinkShare();
         handlePlaceholderLinkShare();
-    } else if (_isSecureFileDropSupportedFolder) {
+    } else if (isSecureFileDropSupportedFolder()) {
         handleSecureFileDropLinkShare();
         handleSecureFileDropLinkShare();
     }
     }
 }
 }
@@ -456,7 +482,7 @@ void ShareModel::setupInternalLinkShare()
         _accountState->account().isNull() ||
         _accountState->account().isNull() ||
         _localPath.isEmpty() ||
         _localPath.isEmpty() ||
         _privateLinkUrl.isEmpty() ||
         _privateLinkUrl.isEmpty() ||
-        _isEncryptedItem) {
+        isEncryptedItem()) {
         return;
         return;
     }
     }
 
 
@@ -466,6 +492,30 @@ void ShareModel::setupInternalLinkShare()
     Q_EMIT internalLinkReady();
     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)
 void ShareModel::slotAddShare(const SharePtr &share)
 {
 {
     if (share.isNull()) {
     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::nameSet, this, [this, shareId]{ slotShareNameSet(shareId); });
         connect(linkShare.data(), &LinkShare::labelSet, this, [this, shareId]{ slotShareLabelSet(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::expireDateSet, this, [this, shareId]{ slotShareExpireDateSet(shareId); });
+        connect(linkShare.data(), &LinkShare::hideDownloadSet, this, [this, shareId] { slotHideDownloadSet(shareId); });
     } else if (const auto userGroupShare = share.objectCast<UserGroupShare>()) {
     } else if (const auto userGroupShare = share.objectCast<UserGroupShare>()) {
         connect(userGroupShare.data(), &UserGroupShare::noteSet, this, [this, shareId]{ slotShareNoteSet(shareId); });
         connect(userGroupShare.data(), &UserGroupShare::noteSet, this, [this, shareId]{ slotShareNoteSet(shareId); });
         connect(userGroupShare.data(), &UserGroupShare::expireDateSet, this, [this, shareId]{ slotShareExpireDateSet(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>()) {
     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");
         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 sharePersistentModelIndex = _shareIdIndexHash.value(shareId);
     const auto shareModelIndex = index(sharePersistentModelIndex.row());
     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)
 void ShareModel::slotSharePasswordSet(const QString &shareId)
@@ -722,6 +774,18 @@ void ShareModel::slotSharePasswordSet(const QString &shareId)
     Q_EMIT dataChanged(shareModelIndex, shareModelIndex, { PasswordProtectEnabledRole, PasswordRole });
     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)
 void ShareModel::slotShareNoteSet(const QString &shareId)
 {
 {
     if (shareId.isEmpty() || !_shareIdIndexHash.contains(shareId)) {
     if (shareId.isEmpty() || !_shareIdIndexHash.contains(shareId)) {
@@ -768,37 +832,56 @@ void ShareModel::slotShareExpireDateSet(const QString &shareId)
 
 
 // ----------------------- Shares modification slots ----------------------- //
 // ----------------------- 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;
         return;
     }
     }
 
 
     auto permissions = share->getPermissions();
     auto permissions = share->getPermissions();
     enable ? permissions |= SharePermissionUpdate : permissions &= ~SharePermissionUpdate;
     enable ? permissions |= SharePermissionUpdate : permissions &= ~SharePermissionUpdate;
 
 
+    setSharePermissionChangeInProgress(share->getId(), true);
     share->setPermissions(permissions);
     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>();
     const auto ptr = share.value<SharePtr>();
     toggleShareAllowEditing(ptr, enable);
     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;
         return;
     }
     }
 
 
     auto permissions = share->getPermissions();
     auto permissions = share->getPermissions();
     enable ? permissions |= SharePermissionShare : permissions &= ~SharePermissionShare;
     enable ? permissions |= SharePermissionShare : permissions &= ~SharePermissionShare;
 
 
+    setSharePermissionChangeInProgress(share->getId(), true);
     share->setPermissions(permissions);
     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>();
     const auto ptr = share.value<SharePtr>();
     toggleShareAllowResharing(ptr, enable);
     toggleShareAllowResharing(ptr, enable);
@@ -867,6 +950,42 @@ void ShareModel::toggleShareNoteToRecipientFromQml(const QVariant &share, const
     toggleShareNoteToRecipient(ptr, enable);
     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
 void ShareModel::setLinkShareLabel(const QSharedPointer<LinkShare> &linkShare, const QString &label) const
 {
 {
     if (linkShare.isNull()) {
     if (linkShare.isNull()) {
@@ -944,7 +1063,7 @@ void ShareModel::setShareNoteFromQml(const QVariant &share, const QString &note)
 
 
 void ShareModel::createNewLinkShare() const
 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.";
         qCWarning(lcShareModel) << "Attempt to create a link share for non-root encrypted folder or a file.";
         return;
         return;
     }
     }
@@ -952,7 +1071,7 @@ void ShareModel::createNewLinkShare() const
     if (_manager) {
     if (_manager) {
         const auto askOptionalPassword = _accountState->account()->capabilities().sharePublicLinkAskOptionalPassword();
         const auto askOptionalPassword = _accountState->account()->capabilities().sharePublicLinkAskOptionalPassword();
         const auto password = askOptionalPassword ? createRandomPassword() : QString();
         const auto password = askOptionalPassword ? createRandomPassword() : QString();
-        if (_isSecureFileDropSupportedFolder) {
+        if (isSecureFileDropSupportedFolder()) {
             _manager->createSecureFileDropShare(_sharePath, {}, password);
             _manager->createSecureFileDropShare(_sharePath, {}, password);
             return;
             return;
         }
         }
@@ -1089,6 +1208,17 @@ bool ShareModel::validCapabilities() const
             _accountState->account()->capabilities().isValid();
             _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
 bool ShareModel::sharingEnabled() const
 {
 {
     return validCapabilities() &&
     return validCapabilities() &&

+ 36 - 7
src/gui/filedetails/sharemodel.h

@@ -57,7 +57,11 @@ public:
         PasswordRole,
         PasswordRole,
         PasswordEnforcedRole,
         PasswordEnforcedRole,
         EditingAllowedRole,
         EditingAllowedRole,
-        IsSecureFileDropLinkRole,
+        CurrentPermissionModeRole,
+        SharedItemTypeRole,
+        IsSharePermissionsChangeInProgress,
+        HideDownloadEnabledRole,
+        IsHideDownloadEnabledChangeInProgress,
     };
     };
     Q_ENUM(Roles)
     Q_ENUM(Roles)
 
 
@@ -79,6 +83,23 @@ public:
         ShareTypeSecureFileDropPlaceholderLink = Share::TypeSecureFileDropPlaceholderLink,
         ShareTypeSecureFileDropPlaceholderLink = Share::TypeSecureFileDropPlaceholderLink,
     };
     };
     Q_ENUM(ShareType);
     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);
     explicit ShareModel(QObject *parent = nullptr);
 
 
@@ -135,16 +156,18 @@ public slots:
     void deleteShare(const OCC::SharePtr &share) const;
     void deleteShare(const OCC::SharePtr &share) const;
     void deleteShareFromQml(const QVariant &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 toggleSharePasswordProtect(const OCC::SharePtr &share, const bool enable);
     void toggleSharePasswordProtectFromQml(const QVariant &share, const bool enable);
     void toggleSharePasswordProtectFromQml(const QVariant &share, const bool enable);
     void toggleShareExpirationDate(const OCC::SharePtr &share, const bool enable) const;
     void toggleShareExpirationDate(const OCC::SharePtr &share, const bool enable) const;
     void toggleShareExpirationDateFromQml(const QVariant &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 toggleShareNoteToRecipient(const OCC::SharePtr &share, const bool enable) const;
     void toggleShareNoteToRecipientFromQml(const QVariant &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 setLinkShareLabel(const QSharedPointer<OCC::LinkShare> &linkShare, const QString &label) const;
     void setLinkShareLabelFromQml(const QVariant &linkShare, const QString &label) const;
     void setLinkShareLabelFromQml(const QVariant &linkShare, const QString &label) const;
@@ -164,6 +187,8 @@ private slots:
     void handleSecureFileDropLinkShare();
     void handleSecureFileDropLinkShare();
     void handleLinkShare();
     void handleLinkShare();
     void setupInternalLinkShare();
     void setupInternalLinkShare();
+    void setSharePermissionChangeInProgress(const QString &shareId, const bool isInProgress);
+    void setHideDownloadEnabledChangeInProgress(const QString &shareId, const bool isInProgress);
 
 
     void slotPropfindReceived(const QVariantMap &result);
     void slotPropfindReceived(const QVariantMap &result);
     void slotServerError(const int code, const QString &message);
     void slotServerError(const int code, const QString &message);
@@ -176,6 +201,7 @@ private slots:
     void slotSharePermissionsSet(const QString &shareId);
     void slotSharePermissionsSet(const QString &shareId);
     void slotSharePasswordSet(const QString &shareId);
     void slotSharePasswordSet(const QString &shareId);
     void slotShareNoteSet(const QString &shareId);
     void slotShareNoteSet(const QString &shareId);
+    void slotHideDownloadSet(const QString &shareId);
     void slotShareNameSet(const QString &shareId);
     void slotShareNameSet(const QString &shareId);
     void slotShareLabelSet(const QString &shareId);
     void slotShareLabelSet(const QString &shareId);
     void slotShareExpireDateSet(const QString &shareId);
     void slotShareExpireDateSet(const QString &shareId);
@@ -187,9 +213,13 @@ private:
     [[nodiscard]] long long enforcedMaxExpireDateForShare(const SharePtr &share) const;
     [[nodiscard]] long long enforcedMaxExpireDateForShare(const SharePtr &share) const;
     [[nodiscard]] bool expireDateEnforcedForShare(const SharePtr &share) const;
     [[nodiscard]] bool expireDateEnforcedForShare(const SharePtr &share) const;
     [[nodiscard]] bool validCapabilities() const;
     [[nodiscard]] bool validCapabilities() const;
+    [[nodiscard]] bool isSecureFileDropSupportedFolder() const;
+    [[nodiscard]] bool isEncryptedItem() const;
 
 
     bool _fetchOngoing = false;
     bool _fetchOngoing = false;
     bool _hasInitialShareFetchCompleted = false;
     bool _hasInitialShareFetchCompleted = false;
+    bool _sharePermissionsChangeInProgress = false;
+    bool _hideDownloadEnabledChangeInProgress = false;
     SharePtr _placeholderLinkShare;
     SharePtr _placeholderLinkShare;
     SharePtr _internalLinkShare;
     SharePtr _internalLinkShare;
     SharePtr _secureFileDropPlaceholderLinkShare;
     SharePtr _secureFileDropPlaceholderLinkShare;
@@ -201,8 +231,7 @@ private:
     QString _sharePath;
     QString _sharePath;
     SharePermissions _maxSharingPermissions;
     SharePermissions _maxSharingPermissions;
     QByteArray _numericFileId;
     QByteArray _numericFileId;
-    bool _isEncryptedItem = false;
-    bool _isSecureFileDropSupportedFolder = false;
+    SharedItemType _sharedItemType = SharedItemType::SharedItemTypeUndefined;
     SyncJournalFileLockInfo _filelockState;
     SyncJournalFileLockInfo _filelockState;
     QString _privateLinkUrl;
     QString _privateLinkUrl;
 
 

+ 12 - 0
src/gui/ocssharejob.cpp

@@ -134,6 +134,18 @@ void OcsShareJob::setLabel(const QString &shareId, const QString &label)
     start();
     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,
 void OcsShareJob::createLinkShare(const QString &path,
     const QString &name,
     const QString &name,
     const QString &password)
     const QString &password)

+ 5 - 0
src/gui/ocssharejob.h

@@ -102,6 +102,11 @@ public:
      */
      */
     void setLabel(const QString &shareId, const QString &label);
     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
      * Create a new link share
      *
      *

+ 25 - 2
src/gui/sharemanager.cpp

@@ -203,7 +203,8 @@ LinkShare::LinkShare(AccountPtr account,
     const QUrl &url,
     const QUrl &url,
     const QDate &expireDate,
     const QDate &expireDate,
     const QString &note,
     const QString &note,
-    const QString &label)
+    const QString &label,
+    const bool hideDownload)
     : Share(account, id, uidowner, ownerDisplayName, path, Share::TypeLink, isPasswordSet, permissions)
     : Share(account, id, uidowner, ownerDisplayName, path, Share::TypeLink, isPasswordSet, permissions)
     , _name(name)
     , _name(name)
     , _token(token)
     , _token(token)
@@ -211,6 +212,7 @@ LinkShare::LinkShare(AccountPtr account,
     , _expireDate(expireDate)
     , _expireDate(expireDate)
     , _url(url)
     , _url(url)
     , _label(label)
     , _label(label)
+    , _hideDownload(hideDownload)
 {
 {
 }
 }
 
 
@@ -239,6 +241,11 @@ QString LinkShare::getLabel() const
     return _label;
     return _label;
 }
 }
 
 
+bool LinkShare::getHideDownload() const
+{
+    return _hideDownload;
+}
+
 void LinkShare::setName(const QString &name)
 void LinkShare::setName(const QString &name)
 {
 {
     createShareJob(&LinkShare::slotNameSet)->setName(getId(), name);
     createShareJob(&LinkShare::slotNameSet)->setName(getId(), name);
@@ -270,6 +277,11 @@ void LinkShare::setLabel(const QString &label)
     createShareJob(&LinkShare::slotLabelSet)->setLabel(getId(), label);
     createShareJob(&LinkShare::slotLabelSet)->setLabel(getId(), label);
 }
 }
 
 
+void LinkShare::setHideDownload(const bool hideDownload)
+{
+    createShareJob(&LinkShare::slotHideDownloadSet)->setHideDownload(getId(), hideDownload);
+}
+
 template <typename LinkShareSlot>
 template <typename LinkShareSlot>
 OcsShareJob *LinkShare::createShareJob(const LinkShareSlot slotFunction) {
 OcsShareJob *LinkShare::createShareJob(const LinkShareSlot slotFunction) {
     auto *job = new OcsShareJob(_account);
     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,
 UserGroupShare::UserGroupShare(AccountPtr account,
     const QString &id,
     const QString &id,
     const QString &owner,
     const QString &owner,
@@ -583,7 +605,8 @@ QSharedPointer<LinkShare> ShareManager::parseLinkShare(const QJsonObject &data)
         url,
         url,
         expireDate,
         expireDate,
         note,
         note,
-        data.value("label").toString()));
+        data.value("label").toString(),
+        data.value("hide_download").toInt() == 1));
 }
 }
 
 
 SharePtr ShareManager::parseShare(const QJsonObject &data) const
 SharePtr ShareManager::parseShare(const QJsonObject &data) const

+ 17 - 1
src/gui/sharemanager.h

@@ -132,6 +132,7 @@ signals:
     void shareDeleted();
     void shareDeleted();
     void serverError(int code, const QString &message);
     void serverError(int code, const QString &message);
     void passwordSet();
     void passwordSet();
+    void hideDownloadSet();
     void passwordSetError(int statusCode, const QString &message);    
     void passwordSetError(int statusCode, const QString &message);    
 
 
 public slots:
 public slots:
@@ -197,6 +198,7 @@ class LinkShare : public Share
     Q_PROPERTY(QString name READ getName WRITE setName NOTIFY nameSet)
     Q_PROPERTY(QString name READ getName WRITE setName NOTIFY nameSet)
     Q_PROPERTY(QString note READ getNote WRITE setNote NOTIFY noteSet)
     Q_PROPERTY(QString note READ getNote WRITE setNote NOTIFY noteSet)
     Q_PROPERTY(QString label READ getLabel WRITE setLabel NOTIFY labelSet)
     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(QDate expireDate READ getExpireDate WRITE setExpireDate NOTIFY expireDateSet)
     Q_PROPERTY(QString token READ getToken CONSTANT)
     Q_PROPERTY(QString token READ getToken CONSTANT)
 
 
@@ -213,7 +215,8 @@ public:
         const QUrl &url,
         const QUrl &url,
         const QDate &expireDate,
         const QDate &expireDate,
         const QString &note,
         const QString &note,
-        const QString &label);
+        const QString &label,
+        const bool hideDownload);
 
 
     /*
     /*
      * Get the share link
      * Get the share link
@@ -250,6 +253,11 @@ public:
      */
      */
     [[nodiscard]] QString getLabel() const;
     [[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.
      * Returns the token of the link share.
      */
      */
@@ -291,18 +299,25 @@ public slots:
      * Set the label of the share link.
      * Set the label of the share link.
      */
      */
     void setLabel(const QString &label);
     void setLabel(const QString &label);
+
+    /*
+     * Set the hideDownload flag of the share link.
+     */
+    void setHideDownload(const bool hideDownload);
     
     
 signals:
 signals:
     void expireDateSet();
     void expireDateSet();
     void noteSet();
     void noteSet();
     void nameSet();
     void nameSet();
     void labelSet();
     void labelSet();
+    void hideDownloadSet();
 
 
 private slots:
 private slots:
     void slotNoteSet(const QJsonDocument &, const QVariant &value);
     void slotNoteSet(const QJsonDocument &, const QVariant &value);
     void slotExpireDateSet(const QJsonDocument &reply, const QVariant &value);
     void slotExpireDateSet(const QJsonDocument &reply, const QVariant &value);
     void slotNameSet(const QJsonDocument &, const QVariant &value);
     void slotNameSet(const QJsonDocument &, const QVariant &value);
     void slotLabelSet(const QJsonDocument &, const QVariant &value);
     void slotLabelSet(const QJsonDocument &, const QVariant &value);
+    void slotHideDownloadSet(const QJsonDocument &jsonDoc, const QVariant &hideDownload);
 
 
 private:
 private:
     QString _name;
     QString _name;
@@ -311,6 +326,7 @@ private:
     QDate _expireDate;
     QDate _expireDate;
     QUrl _url;
     QUrl _url;
     QString _label;
     QString _label;
+    bool _hideDownload = false;
 };
 };
 
 
 class UserGroupShare : public Share
 class UserGroupShare : public Share

+ 5 - 0
theme/Style/Style.qml

@@ -122,6 +122,11 @@ QtObject {
     readonly property int unifiedSearchResultSectionItemVerticalPadding: 8
     readonly property int unifiedSearchResultSectionItemVerticalPadding: 8
     readonly property int unifiedSearchResultNothingFoundHorizontalMargin: 10
     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 var fontMetrics: FontMetrics {}
 
 
     readonly property int activityContentSpace: 4
     readonly property int activityContentSpace: 4