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