1import QtQml 2.12 2import QtQuick 2.9 3import QtQuick.Controls 2.2 4import QtQuick.Layouts 1.2 5import Style 1.0 6import com.nextcloud.desktopclient 1.0 7 8MouseArea { 9 id: activityMouseArea 10 11 readonly property int maxActionButtons: 2 12 property Flickable flickable 13 14 signal fileActivityButtonClicked(string absolutePath) 15 16 enabled: (path !== "" || link !== "") 17 hoverEnabled: true 18 19 Rectangle { 20 anchors.fill: parent 21 color: (parent.containsMouse ? Style.lightHover : "transparent") 22 } 23 24 RowLayout { 25 id: activityItem 26 27 readonly property variant links: model.links 28 29 readonly property int itemIndex: model.index 30 31 width: activityMouseArea.width 32 height: Style.trayWindowHeaderHeight 33 spacing: 0 34 35 Accessible.role: Accessible.ListItem 36 Accessible.name: path !== "" ? qsTr("Open %1 locally").arg(displayPath) 37 : message 38 Accessible.onPressAction: activityMouseArea.clicked() 39 40 Image { 41 id: activityIcon 42 Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter 43 Layout.leftMargin: 20 44 Layout.preferredWidth: shareButton.icon.width 45 Layout.preferredHeight: shareButton.icon.height 46 verticalAlignment: Qt.AlignCenter 47 cache: true 48 source: icon 49 sourceSize.height: 64 50 sourceSize.width: 64 51 } 52 53 Column { 54 id: activityTextColumn 55 Layout.leftMargin: 14 56 Layout.topMargin: 4 57 Layout.bottomMargin: 4 58 Layout.fillWidth: true 59 spacing: 4 60 Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter 61 62 Text { 63 id: activityTextTitle 64 text: (type === "Activity" || type === "Notification") ? subject : message 65 width: parent.width 66 elide: Text.ElideRight 67 font.pixelSize: Style.topLinePixelSize 68 color: activityTextTitleColor 69 } 70 71 Text { 72 id: activityTextInfo 73 text: (type === "Sync") ? displayPath 74 : (type === "File") ? subject 75 : (type === "Notification") ? message 76 : "" 77 height: (text === "") ? 0 : activityTextTitle.height 78 width: parent.width 79 elide: Text.ElideRight 80 font.pixelSize: Style.subLinePixelSize 81 } 82 83 Text { 84 id: activityTextDateTime 85 text: dateTime 86 height: (text === "") ? 0 : activityTextTitle.height 87 width: parent.width 88 elide: Text.ElideRight 89 font.pixelSize: Style.subLinePixelSize 90 color: "#808080" 91 } 92 } 93 94 RowLayout { 95 id: activityActionsLayout 96 spacing: 0 97 Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter 98 Layout.minimumWidth: 28 99 Layout.fillWidth: true 100 101 function actionButtonIcon(actionIndex) { 102 const verb = String(model.links[actionIndex].verb); 103 if (verb === "WEB" && (model.objectType === "chat" || model.objectType === "call")) { 104 return "qrc:///client/theme/reply.svg"; 105 } else if (verb === "DELETE") { 106 return "qrc:///client/theme/close.svg"; 107 } 108 109 return "qrc:///client/theme/confirm.svg"; 110 } 111 112 Repeater { 113 model: activityItem.links.length > maxActionButtons ? 1 : activityItem.links.length 114 115 ActivityActionButton { 116 id: activityActionButton 117 118 readonly property int actionIndex: model.index 119 readonly property bool primary: model.index === 0 && String(activityItem.links[actionIndex].verb) !== "DELETE" 120 121 Layout.fillHeight: true 122 123 text: !primary ? "" : activityItem.links[actionIndex].label 124 125 imageSource: !primary ? activityActionsLayout.actionButtonIcon(actionIndex) : "" 126 127 textColor: primary ? Style.ncBlue : "black" 128 textColorHovered: Style.lightHover 129 130 textBorderColor: Style.ncBlue 131 132 textBgColor: "transparent" 133 textBgColorHovered: Style.ncBlue 134 135 tooltipText: activityItem.links[actionIndex].label 136 137 Layout.minimumWidth: primary ? 80 : -1 138 Layout.minimumHeight: parent.height 139 140 Layout.preferredWidth: primary ? -1 : parent.height 141 142 onClicked: activityModel.triggerAction(activityItem.itemIndex, actionIndex) 143 } 144 145 } 146 147 Button { 148 id: shareButton 149 150 Layout.preferredWidth: parent.height 151 Layout.fillHeight: true 152 Layout.alignment: Qt.AlignRight 153 flat: true 154 hoverEnabled: true 155 visible: displayActions && (path !== "") 156 display: AbstractButton.IconOnly 157 icon.source: "qrc:///client/theme/share.svg" 158 icon.color: "transparent" 159 background: Rectangle { 160 color: parent.hovered ? Style.lightHover : "transparent" 161 } 162 ToolTip.visible: hovered 163 ToolTip.delay: Qt.styleHints.mousePressAndHoldInterval 164 ToolTip.text: qsTr("Open share dialog") 165 onClicked: Systray.openShareDialog(displayPath, absolutePath) 166 167 Accessible.role: Accessible.Button 168 Accessible.name: qsTr("Share %1").arg(displayPath) 169 Accessible.onPressAction: shareButton.clicked() 170 } 171 172 Button { 173 id: moreActionsButton 174 175 Layout.preferredWidth: parent.height 176 Layout.preferredHeight: parent.height 177 Layout.alignment: Qt.AlignRight 178 179 flat: true 180 hoverEnabled: true 181 visible: displayActions && ((path !== "") || (activityItem.links.length > maxActionButtons)) 182 display: AbstractButton.IconOnly 183 icon.source: "qrc:///client/theme/more.svg" 184 icon.color: "transparent" 185 background: Rectangle { 186 color: parent.hovered ? Style.lightHover : "transparent" 187 } 188 ToolTip.visible: hovered 189 ToolTip.delay: Qt.styleHints.mousePressAndHoldInterval 190 ToolTip.text: qsTr("Show more actions") 191 192 Accessible.role: Accessible.Button 193 Accessible.name: qsTr("Show more actions") 194 Accessible.onPressAction: moreActionsButton.clicked() 195 196 onClicked: moreActionsButtonContextMenu.popup(); 197 198 Connections { 199 target: flickable 200 201 function onMovementStarted() { 202 moreActionsButtonContextMenu.close(); 203 } 204 } 205 206 Container { 207 id: moreActionsButtonContextMenuContainer 208 visible: moreActionsButtonContextMenu.opened 209 210 width: moreActionsButtonContextMenu.width 211 height: moreActionsButtonContextMenu.height 212 anchors.right: moreActionsButton.right 213 anchors.top: moreActionsButton.top 214 215 Menu { 216 id: moreActionsButtonContextMenu 217 anchors.centerIn: parent 218 219 // transform model to contain indexed actions with primary action filtered out 220 function actionListToContextMenuList(actionList) { 221 // early out with non-altered data 222 if (activityItem.links.length <= maxActionButtons) { 223 return actionList; 224 } 225 226 // add index to every action and filter 'primary' action out 227 var reducedActionList = actionList.reduce(function(reduced, action, index) { 228 if (!action.primary) { 229 var actionWithIndex = { actionIndex: index, label: action.label }; 230 reduced.push(actionWithIndex); 231 } 232 return reduced; 233 }, []); 234 235 236 return reducedActionList; 237 } 238 239 MenuItem { 240 text: qsTr("View activity") 241 onClicked: fileActivityButtonClicked(absolutePath) 242 } 243 244 Repeater { 245 id: moreActionsButtonContextMenuRepeater 246 247 model: moreActionsButtonContextMenu.actionListToContextMenuList(activityItem.links) 248 249 delegate: MenuItem { 250 id: moreActionsButtonContextMenuEntry 251 text: model.modelData.label 252 onTriggered: activityModel.triggerAction(activityItem.itemIndex, model.modelData.actionIndex) 253 } 254 } 255 } 256 } 257 } 258 } 259 } 260} 261