Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
41aa7ad
feat(socketapii): add file actions option to list of options for files.
camilasan Jun 23, 2025
b5caa1e
feat(declarativeui): style file actions window.
camilasan Sep 3, 2025
49fba7f
feat(declarativeui): improve the looks of the file actions Window.
camilasan Sep 3, 2025
b5f646a
fix(declarativeui/fileactions): file actions context menu.
camilasan Sep 4, 2025
088bdc7
feat(declarativeui): add logging category to FileActionsModel.
camilasan Sep 17, 2025
d14d741
feat(declarativeui/fileactions): return default icon when server does…
camilasan Sep 18, 2025
ea59b6b
fix(declarativeui/fileactions): parse response with declarative UI el…
camilasan Sep 30, 2025
abd44e9
refactor(declarativeui): remove unused DeclarativeUi class.
camilasan Oct 1, 2025
50621a5
fix(declarativeui): files license.
camilasan Oct 1, 2025
8707fe5
refactor(declarativeui): remove Declarative UI menu item.
camilasan Oct 1, 2025
776a5b1
fix(capabilities): update capabilities with new json key + adjust mim…
camilasan Jan 20, 2026
cd70372
fix(declarativeui): use EnforcedPlainTextLabel instead of Label.
camilasan Jan 21, 2026
804cb9c
fix(capabilities): an empty mimetype_filters means the action is avai…
camilasan Jan 21, 2026
fc1a41c
fix(declarativeui/fileactions): handle the new params format.
camilasan Jan 21, 2026
d681705
style(integration): rename from declarativeui to integration.
camilasan Jan 31, 2026
55aba16
fix(integratio): return true if there isn't an empty client_integrati…
camilasan Feb 1, 2026
b5a78c2
feat(integration): do not list file actions if the server doesn't sup…
camilasan Feb 1, 2026
1a1e493
style(tray): modernize ActivityListModel::data.
camilasan Feb 1, 2026
705eb8e
fix(integration): use ActivityData function to retrieve server icon.
camilasan Feb 2, 2026
5580efc
refactor(tray): modernize Activity::relativeServerFileTypeIconPath.
camilasan Feb 2, 2026
83aa524
feat(integration): align icons and make sure they all have the same s…
camilasan Feb 2, 2026
441eda5
fix(integration): address review's comments.
camilasan Feb 3, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion REUSE.toml
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ SPDX-FileCopyrightText = "2016 Nextcloud GmbH"
SPDX-License-Identifier = "LicenseRef-NextcloudTrademarks"

[[annotations]]
path = ["theme/white/error.svg", "theme/black/error.svg","theme/white/warning.svg", "theme/black/warning.svg", "theme/white/info.svg", "theme/black/info.svg", "theme/info.svg", "theme/white/nextcloud/*.svg", "theme/black/nextcloud/*.svg", "theme/colored/nextcloud/*.svg", "theme/black/label.svg", "theme/white/label.svg", "theme/colored/user-status-*.svg", "theme/account.svg","theme/add.svg","theme/change.svg","theme/chevron-double-up.svg","theme/close.svg","theme/confirm.svg","theme/copy.svg","theme/delete.svg","theme/external.svg","theme/files.svg","theme/lock-broken.svg","theme/lock-http.svg","theme/lock-https.svg","theme/lock.svg","theme/magnifying-glass.svg","theme/more.svg","theme/network.svg","theme/public.svg","theme/reply.svg","theme/send.svg","theme/settings.svg","theme/share.svg","theme/sync-arrow.svg", "theme/black/account-group.svg","theme/black/clear.svg","theme/black/expand-less-black.svg","theme/black/folder-group.svg","theme/black/search.svg", "theme/colored/add-bordered.svg", "theme/colored/change-bordered.svg", "theme/colored/delete-bordered.svg", "theme/colored/delete.svg", "theme/*/activity.svg", "theme/*/add.svg","theme/*/bell.svg","theme/*/calendar.svg","theme/*/caret-down.svg","theme/*/change.svg","theme/*/close.svg","theme/*/comment.svg","theme/*/confirm.svg","theme/*/control-next.svg","theme/*/control-prev.svg","theme/*/edit.svg","theme/*/email.svg","theme/*/external.png","theme/*/external.svg","theme/*/external@2x.png","theme/*/folder.png","theme/*/folder.svg","theme/*/folder@2x.png","theme/*/more-apps.svg","theme/*/nc-assistant-app.svg","theme/*/settings.svg","theme/*/user.svg","theme/*/wizard-files.png","theme/*/wizard-files.svg","theme/*/wizard-files@2x.png","theme/*/wizard-groupware.png","theme/*/wizard-groupware.svg","theme/*/wizard-groupware@2x.png", "theme/cfapishellext_custom_states/0-locked.svg","theme/cfapishellext_custom_states/1-shared.svg","theme/cfapishellext_custom_states/1024-0-locked.png","theme/cfapishellext_custom_states/1024-1-shared.png","theme/cfapishellext_custom_states/128-0-locked.png","theme/cfapishellext_custom_states/128-1-shared.png","theme/cfapishellext_custom_states/24-0-locked.png","theme/cfapishellext_custom_states/24-1-shared.png","theme/cfapishellext_custom_states/256-0-locked.png","theme/cfapishellext_custom_states/256-1-shared.png","theme/cfapishellext_custom_states/32-0-locked.png","theme/cfapishellext_custom_states/32-1-shared.png","theme/cfapishellext_custom_states/40-0-locked.png","theme/cfapishellext_custom_states/40-1-shared.png","theme/cfapishellext_custom_states/48-0-locked.png","theme/cfapishellext_custom_states/48-1-shared.png","theme/cfapishellext_custom_states/512-0-locked.png","theme/cfapishellext_custom_states/512-1-shared.png","theme/cfapishellext_custom_states/64-0-locked.png","theme/cfapishellext_custom_states/64-1-shared.png"]
path = ["theme/white/error.svg", "theme/black/error.svg","theme/white/warning.svg", "theme/black/warning.svg", "theme/white/info.svg", "theme/black/info.svg", "theme/info.svg", "theme/white/nextcloud/*.svg", "theme/black/nextcloud/*.svg", "theme/colored/nextcloud/*.svg", "theme/black/label.svg", "theme/white/label.svg", "theme/colored/user-status-*.svg", "theme/account.svg","theme/add.svg","theme/change.svg","theme/chevron-double-up.svg","theme/close.svg","theme/confirm.svg","theme/copy.svg","theme/delete.svg","theme/external.svg","theme/files.svg","theme/lock-broken.svg","theme/lock-http.svg","theme/lock-https.svg","theme/lock.svg","theme/magnifying-glass.svg","theme/more.svg","theme/network.svg","theme/public.svg","theme/reply.svg","theme/send.svg","theme/settings.svg","theme/share.svg","theme/sync-arrow.svg", "theme/black/account-group.svg","theme/black/clear.svg","theme/black/expand-less-black.svg","theme/black/folder-group.svg","theme/black/search.svg", "theme/colored/add-bordered.svg", "theme/colored/change-bordered.svg", "theme/colored/delete-bordered.svg", "theme/colored/delete.svg", "theme/*/activity.svg", "theme/*/add.svg","theme/*/bell.svg","theme/*/calendar.svg","theme/*/caret-down.svg","theme/*/change.svg","theme/*/close.svg","theme/*/comment.svg","theme/*/confirm.svg","theme/*/control-next.svg","theme/*/control-prev.svg","theme/*/edit.svg","theme/*/email.svg","theme/*/external.png","theme/*/external.svg","theme/*/external@2x.png","theme/*/folder.png","theme/*/folder.svg","theme/*/folder@2x.png","theme/*/more-apps.svg","theme/*/nc-assistant-app.svg","theme/*/settings.svg","theme/*/user.svg","theme/*/wizard-files.png","theme/*/wizard-files.svg","theme/*/wizard-files@2x.png","theme/*/wizard-groupware.png","theme/*/wizard-groupware.svg","theme/*/wizard-groupware@2x.png", "theme/cfapishellext_custom_states/0-locked.svg","theme/cfapishellext_custom_states/1-shared.svg","theme/cfapishellext_custom_states/1024-0-locked.png","theme/cfapishellext_custom_states/1024-1-shared.png","theme/cfapishellext_custom_states/128-0-locked.png","theme/cfapishellext_custom_states/128-1-shared.png","theme/cfapishellext_custom_states/24-0-locked.png","theme/cfapishellext_custom_states/24-1-shared.png","theme/cfapishellext_custom_states/256-0-locked.png","theme/cfapishellext_custom_states/256-1-shared.png","theme/cfapishellext_custom_states/32-0-locked.png","theme/cfapishellext_custom_states/32-1-shared.png","theme/cfapishellext_custom_states/40-0-locked.png","theme/cfapishellext_custom_states/40-1-shared.png","theme/cfapishellext_custom_states/48-0-locked.png","theme/cfapishellext_custom_states/48-1-shared.png","theme/cfapishellext_custom_states/512-0-locked.png","theme/cfapishellext_custom_states/512-1-shared.png","theme/cfapishellext_custom_states/64-0-locked.png","theme/cfapishellext_custom_states/64-1-shared.png", "theme/backup.svg", "theme/convert_to_text.svg", "theme/file-open.svg"]
precedence = "aggregate"
SPDX-FileCopyrightText = "2018-2025 Google LLC"
SPDX-License-Identifier = "Apache-2.0"
1 change: 1 addition & 0 deletions resources.qrc
Original file line number Diff line number Diff line change
Expand Up @@ -61,5 +61,6 @@
<file>src/gui/ConflictItemFileInfo.qml</file>
<file>src/gui/macOS/ui/FileProviderSettings.qml</file>
<file>src/gui/macOS/ui/FileProviderFileDelegate.qml</file>
<file>src/gui/integration/FileActionsWindow.qml</file>
</qresource>
</RCC>
2 changes: 2 additions & 0 deletions src/gui/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,8 @@ set(client_SRCS
wizard/linklabel.cpp
wizard/wizardproxysettingsdialog.h
wizard/wizardproxysettingsdialog.cpp
integration/fileactionsmodel.h
integration/fileactionsmodel.cpp
Comment thread
camilasan marked this conversation as resolved.
)

if (NOT DISABLE_ACCOUNT_MIGRATION)
Expand Down
3 changes: 3 additions & 0 deletions src/gui/application.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
/*
* SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors
* SPDX-FileCopyrightText: 2014 ownCloud GmbH
Expand Down Expand Up @@ -432,6 +432,9 @@
connect(FolderMan::instance()->socketApi(), &SocketApi::fileActivityCommandReceived,
_gui.data(), &ownCloudGui::slotShowFileActivityDialog);

connect(FolderMan::instance()->socketApi(), &SocketApi::fileActionsCommandReceived,
_gui.data(), &ownCloudGui::slotShowFileActionsDialog);

// startup procedure.
connect(&_checkConnectionTimer, &QTimer::timeout, this, &Application::slotCheckConnection);
_checkConnectionTimer.setInterval(ConnectionValidator::DefaultCallingIntervalMsec); // check for connection every 32 seconds.
Expand Down
261 changes: 261 additions & 0 deletions src/gui/integration/FileActionsWindow.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,261 @@
/*
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: GPL-2.0-or-later
*/

pragma ComponentBehavior: Bound

import QtQuick
import QtQuick.Window
import QtQuick.Layouts
import QtQuick.Controls
import Qt5Compat.GraphicalEffects
import com.nextcloud.desktopclient
import Style
import "./../tray"

ApplicationWindow {
id: root
height: Style.filesActionsHeight
width: Style.filesActionsWidth
flags: Systray.useNormalWindow ? Qt.Window : Qt.Dialog | Qt.FramelessWindowHint
Comment thread
camilasan marked this conversation as resolved.
visible: true
color: "transparent"

property var accountState: ({})
property string localPath: ""
property string shortLocalPath: ""

readonly property int windowRadius: Systray.useNormalWindow ? 0.0 : Style.trayWindowRadius

title: qsTr("File actions for %1").arg(root.shortLocalPath)

FileActionsModel {
id: fileActionModel
accountState: root.accountState
localPath: root.localPath
}

background: Rectangle {
id: maskSource
radius: root.windowRadius
border.width: Style.trayWindowBorderWidth
border.color: palette.dark
color: palette.window
}

OpacityMask {
anchors.fill: parent
anchors.margins: Style.trayWindowBorderWidth
source: maskSourceItem
maskSource: maskSource
}

Rectangle {
id: maskSourceItem
anchors.fill: parent
anchors.margins: Style.standardSpacing
radius: root.windowRadius
clip: true
color: Style.colorWithoutTransparency(palette.base)

ColumnLayout {
id: windowContent
anchors.fill: parent
anchors.margins: Style.standardSpacing

RowLayout {
id: windowHeader
Layout.fillWidth: true
spacing: Style.standardSpacing

Image {
source: fileActionModel.fileIcon + palette.windowText
Layout.preferredWidth: Style.minimumActivityItemHeight
Layout.preferredHeight: Style.minimumActivityItemHeight
Layout.alignment: Qt.AlignVCenter
Layout.margins: Style.extraSmallSpacing
}

EnforcedPlainTextLabel {
id: headerLocalPath
text: root.shortLocalPath
elide: Text.ElideRight
font.bold: true
font.pixelSize: Style.pixelSize
color: palette.text
Layout.fillWidth: true
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
}

Button {
id: closeButton
flat: true
padding: Style.extraSmallSpacing
spacing: 0
icon.source: "image://svgimage-custom-color/close.svg/" + palette.windowText
icon.width: Style.extraSmallIconSize
icon.height: Style.extraSmallIconSize
Layout.alignment: Qt.AlignTop | Qt.AlignRight
Layout.rightMargin: Style.extraSmallSpacing
Layout.topMargin: Style.extraSmallSpacing
onClicked: root.close()
background: Rectangle {
color: "transparent"
radius: root.windowRadius
border.width: closeButton.hovered ? Style.trayWindowBorderWidth : 0
border.color: palette.dark
anchors.fill: parent
Layout.margins: Style.extraSmallSpacing
}
}
}

Rectangle {
id: lineTop
Layout.fillWidth: true
Layout.minimumHeight: Style.extraExtraSmallSpacing
color: palette.dark
}

ListView {
id: fileActionsView
model: fileActionModel
clip: true
spacing: Style.trayHorizontalMargin
Layout.fillWidth: true
Layout.fillHeight: true
delegate: fileActionsDelegate
}

Button {
id: responseButton
visible: responseText.text !== ""
flat: true
Layout.fillWidth: true
implicitHeight: responseContent.implicitHeight

padding: Style.standardSpacing
leftPadding: Style.standardSpacing
rightPadding: Style.standardSpacing
spacing: Style.standardSpacing

background: Rectangle {
id: responseBorder
radius: root.windowRadius
border.width: Style.trayWindowBorderWidth
border.color: palette.dark
color: palette.window
Layout.fillWidth: true
}

contentItem: RowLayout {
id: responseContent
anchors.fill: parent
anchors.margins: Style.smallSpacing
spacing: Style.standardSpacing
Layout.fillWidth: true
Layout.minimumHeight: Style.accountAvatarStateIndicatorSize

Image {
source: "image://svgimage-custom-color/backup.svg/" + palette.windowText
Layout.preferredWidth: Style.minimumActivityItemHeight
Layout.preferredHeight: Style.minimumActivityItemHeight
Layout.alignment: Qt.AlignLeft
Layout.bottomMargin: Style.standardSpacing
}

Text {
id: responseText
text: fileActionModel.responseLabel
textFormat: Text.RichText
color: palette.text
font.pointSize: Style.pixelSize
font.underline: true
wrapMode: Text.WordWrap
Layout.fillWidth: true
bottomPadding: Style.standardSpacing
}
}

MouseArea {
id: responseArea
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: Qt.openUrlExternally(fileActionModel.responseUrl)
}
}
}
}

Component {
id: fileActionsDelegate

RowLayout {
id: fileAction
Layout.fillWidth: true
height: implicitHeight
width: parent.width

required property string name
required property int index
required property string icon

Button {
id: fileActionButton
flat: true
Layout.fillWidth: true
implicitHeight: Style.activityListButtonHeight

padding: Style.standardSpacing

contentItem: Row {
id: fileActionsContent
anchors.fill: parent
anchors.topMargin: Style.standardSpacing
anchors.rightMargin: Style.standardSpacing
anchors.bottomMargin: Style.standardSpacing
anchors.leftMargin: Style.extraSmallSpacing
spacing: Style.standardSpacing
Layout.fillWidth: true

Image {
source: fileAction.icon + palette.windowText
width: Style.minimumActivityItemHeight
height: Style.minimumActivityItemHeight
fillMode: Image.PreserveAspectFit
Layout.preferredWidth: Style.minimumActivityItemHeight
Layout.preferredHeight: Style.minimumActivityItemHeight
anchors.verticalCenter: parent.verticalCenter
}

EnforcedPlainTextLabel {
text: fileAction.name
color: palette.text
font.pixelSize: Style.defaultFontPtSize
verticalAlignment: Text.AlignVCenter
anchors.verticalCenter: parent.verticalCenter
}
}

background: Rectangle {
color: "transparent"
radius: root.windowRadius
border.width: fileActionButton.hovered ? Style.trayWindowBorderWidth : 0
border.color: palette.dark
anchors.margins: Style.standardSpacing
height: parent.height
width: parent.width
}

MouseArea {
id: fileActionMouseArea
anchors.fill: parent
anchors.margins: Style.standardSpacing
cursorShape: Qt.PointingHandCursor
onClicked: fileActionModel.createRequest(fileAction.index)
}
}
}
}
}
Loading