mirror of
https://github.com/nextcloud/desktop.git
synced 2024-11-21 20:45:51 +03:00
use a much more compact layout for activities
Signed-off-by: Matthieu Gallien <matthieu.gallien@nextcloud.com>
This commit is contained in:
parent
9dd5cc35f8
commit
607d0da672
10 changed files with 216 additions and 208 deletions
|
@ -30,8 +30,6 @@ ItemDelegate {
|
|||
}
|
||||
|
||||
contentItem: ColumnLayout {
|
||||
id: contentLayout
|
||||
|
||||
spacing: Style.activityContentSpace
|
||||
|
||||
ActivityItemContent {
|
||||
|
@ -57,7 +55,7 @@ ItemDelegate {
|
|||
|
||||
Layout.preferredWidth: Style.talkReplyTextFieldPreferredWidth
|
||||
Layout.preferredHeight: Style.talkReplyTextFieldPreferredHeight
|
||||
Layout.leftMargin: Style.trayListItemIconSize + activityContent.spacing
|
||||
Layout.leftMargin: Style.trayListItemIconSize + Style.trayHorizontalMargin
|
||||
|
||||
sourceComponent: TalkReplyTextField {
|
||||
onSendReply: {
|
||||
|
@ -66,28 +64,5 @@ ItemDelegate {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
ActivityItemActions {
|
||||
id: activityActions
|
||||
|
||||
visible: !root.isFileActivityList && model.linksForActionButtons.length > 0 && !isTalkReplyOptionVisible
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: Style.trayListItemIconSize + activityContent.spacing
|
||||
Layout.preferredHeight: Style.standardPrimaryButtonHeight
|
||||
|
||||
displayActions: model.displayActions
|
||||
objectType: model.objectType
|
||||
linksForActionButtons: model.linksForActionButtons
|
||||
linksContextMenu: model.linksContextMenu
|
||||
|
||||
maxActionButtons: activityModel.maxActionButtons
|
||||
|
||||
flickable: root.flickable
|
||||
|
||||
onTriggerAction: activityModel.slotTriggerAction(model.activityIndex, actionIndex)
|
||||
|
||||
onShowReplyField: root.isTalkReplyOptionVisible = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,11 +5,9 @@ import QtQuick.Layouts 1.15
|
|||
import Style 1.0
|
||||
import com.nextcloud.desktopclient 1.0
|
||||
|
||||
RowLayout {
|
||||
Repeater {
|
||||
id: root
|
||||
|
||||
spacing: 20
|
||||
|
||||
property string objectType: ""
|
||||
property variant linksForActionButtons: []
|
||||
property variant linksContextMenu: []
|
||||
|
@ -24,71 +22,29 @@ RowLayout {
|
|||
signal triggerAction(int actionIndex)
|
||||
signal showReplyField()
|
||||
|
||||
Repeater {
|
||||
id: actionsRepeater
|
||||
// a max of maxActionButtons will get dispayed as separate buttons
|
||||
model: root.linksForActionButtons
|
||||
|
||||
ActivityActionButton {
|
||||
CustomButton {
|
||||
id: activityActionButton
|
||||
|
||||
Layout.minimumWidth: primaryButton ? Style.activityItemActionPrimaryButtonMinWidth : Style.activityItemActionSecondaryButtonMinWidth
|
||||
Layout.preferredHeight: parent.height
|
||||
property string verb: model.modelData.verb
|
||||
property bool isTalkReplyButton: verb === "REPLY"
|
||||
|
||||
verb: model.modelData.verb
|
||||
primaryButton: (model.index === 0 && verb !== "DELETE") || model.modelData.primary
|
||||
isTalkReplyButton: verb === "REPLY"
|
||||
Layout.alignment: Qt.AlignTop | Qt.AlignRight
|
||||
|
||||
hoverEnabled: true
|
||||
padding: Style.smallSpacing
|
||||
display: Button.TextOnly
|
||||
|
||||
text: model.modelData.label
|
||||
|
||||
adjustedHeaderColor: Style.adjustedCurrentUserHeaderColor
|
||||
|
||||
icon.source: model.modelData.imageSource ? model.modelData.imageSource + Style.adjustedCurrentUserHeaderColor : ""
|
||||
imageSourceHover: model.modelData.imageSourceHovered ? model.modelData.imageSourceHovered + Style.currentUserHeaderTextColor : ""
|
||||
|
||||
onClicked: isTalkReplyButton ? root.showReplyField() : root.triggerAction(model.index)
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
// actions that do not fit maxActionButtons limit, must be put into a context menu
|
||||
id: moreActionsButtonContainer
|
||||
|
||||
Layout.preferredWidth: parent.height
|
||||
Layout.topMargin: Style.roundedButtonBackgroundVerticalMargins
|
||||
Layout.bottomMargin: Style.roundedButtonBackgroundVerticalMargins
|
||||
Layout.fillHeight: true
|
||||
|
||||
active: root.displayActions && (root.linksContextMenu.length > 0)
|
||||
visible: active
|
||||
|
||||
sourceComponent: Button {
|
||||
id: moreActionsButton
|
||||
|
||||
icon.source: "qrc:///client/theme/more.svg"
|
||||
icon.color: Style.ncTextColor
|
||||
|
||||
background: Rectangle {
|
||||
color: parent.hovered ? Style.lightHover : root.moreActionsButtonColor
|
||||
radius: width / 2
|
||||
}
|
||||
|
||||
NCToolTip {
|
||||
visible: parent.hovered
|
||||
text: qsTr("Show more actions")
|
||||
}
|
||||
|
||||
Accessible.name: qsTr("Show more actions")
|
||||
|
||||
onClicked: moreActionsButtonContextMenu.popup(moreActionsButton.x, moreActionsButton.y);
|
||||
|
||||
Connections {
|
||||
target: root.flickable
|
||||
|
||||
function onMovementStarted() {
|
||||
moreActionsButtonContextMenu.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
textColor: Style.adjustedCurrentUserHeaderColor
|
||||
textColorHovered: Style.currentUserHeaderTextColor
|
||||
contentsFont.bold: true
|
||||
bgColor: Style.currentUserHeaderColor
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ import QtGraphicalEffects 1.15
|
|||
import Style 1.0
|
||||
import com.nextcloud.desktopclient 1.0
|
||||
|
||||
RowLayout {
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property variant activityData: {{}}
|
||||
|
@ -23,17 +23,20 @@ RowLayout {
|
|||
|
||||
signal dismissButtonClicked()
|
||||
|
||||
spacing: Style.trayHorizontalMargin
|
||||
|
||||
Item {
|
||||
id: thumbnailItem
|
||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
|
||||
Layout.preferredWidth: root.iconSize
|
||||
Layout.preferredHeight: model.thumbnail && model.thumbnail.isMimeTypeIcon ? root.iconSize * 0.9 : root.iconSize
|
||||
|
||||
readonly property int imageWidth: width * (1 - Style.thumbnailImageSizeReduction)
|
||||
readonly property int imageHeight: height * (1 - Style.thumbnailImageSizeReduction)
|
||||
readonly property int thumbnailRadius: model.thumbnail && model.thumbnail.isUserAvatar ? width / 2 : 3
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
|
||||
implicitHeight: model.thumbnail && model.thumbnail.isMimeTypeIcon ? root.iconSize * 0.9 : root.iconSize
|
||||
implicitWidth: root.iconSize
|
||||
|
||||
Loader {
|
||||
id: thumbnailImageLoader
|
||||
anchors.fill: parent
|
||||
|
@ -112,49 +115,58 @@ RowLayout {
|
|||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
id: activityTextColumn
|
||||
ColumnLayout {
|
||||
id: activityContentLayout
|
||||
|
||||
Layout.topMargin: Style.activityContentSpace
|
||||
anchors.left: thumbnailItem.right
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
|
||||
spacing: Style.smallSpacing
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
|
||||
Layout.maximumWidth: activityContentLayout.width
|
||||
|
||||
spacing: Style.activityContentSpace
|
||||
spacing: Style.trayHorizontalMargin
|
||||
|
||||
EnforcedPlainTextLabel {
|
||||
id: activityTextTitle
|
||||
text: (root.activityData.type === "Activity" || root.activityData.type === "Notification") ? root.activityData.subject : root.activityData.message
|
||||
height: (text === "") ? 0 : implicitHeight
|
||||
width: parent.width
|
||||
|
||||
Layout.maximumWidth: activityContentLayout.width - Style.trayHorizontalMargin -
|
||||
(activityTextDateTime.visible ? activityTextDateTime.width + Style.trayHorizontalMargin : 0) -
|
||||
(dismissActionButton.visible ? dismissActionButton.width + Style.trayHorizontalMargin : 0)
|
||||
Layout.alignment: Qt.AlignTop | Qt.AlignLeft
|
||||
|
||||
elide: Text.ElideRight
|
||||
wrapMode: Text.Wrap
|
||||
maximumLineCount: 2
|
||||
maximumLineCount: 1
|
||||
font.pixelSize: Style.topLinePixelSize
|
||||
color: Style.ncTextColor
|
||||
visible: text !== ""
|
||||
|
||||
NCToolTip {
|
||||
text: parent.text
|
||||
visible: parent.hovered
|
||||
}
|
||||
}
|
||||
|
||||
EnforcedPlainTextLabel {
|
||||
id: activityTextInfo
|
||||
text: (root.activityData.type === "Sync") ? root.activityData.displayPath
|
||||
: (root.activityData.type === "File") ? root.activityData.subject
|
||||
: (root.activityData.type === "Notification") ? root.activityData.message
|
||||
: ""
|
||||
height: (text === "") ? 0 : implicitHeight
|
||||
width: parent.width
|
||||
elide: Text.ElideRight
|
||||
wrapMode: Text.Wrap
|
||||
maximumLineCount: 2
|
||||
font.pixelSize: Style.subLinePixelSize
|
||||
color: Style.ncTextColor
|
||||
visible: text !== ""
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: -Style.trayHorizontalMargin
|
||||
}
|
||||
|
||||
EnforcedPlainTextLabel {
|
||||
id: activityTextDateTime
|
||||
text: root.activityData.dateTime
|
||||
|
||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
|
||||
height: (text === "") ? 0 : implicitHeight
|
||||
width: parent.width
|
||||
|
||||
text: root.activityData.dateTime
|
||||
elide: Text.ElideRight
|
||||
wrapMode: Text.Wrap
|
||||
maximumLineCount: 2
|
||||
|
@ -163,59 +175,123 @@ RowLayout {
|
|||
visible: text !== ""
|
||||
}
|
||||
|
||||
EnforcedPlainTextLabel {
|
||||
id: talkReplyMessageSent
|
||||
text: root.activityData.messageSent
|
||||
height: (text === "") ? 0 : implicitHeight
|
||||
width: parent.width
|
||||
elide: Text.ElideRight
|
||||
wrapMode: Text.Wrap
|
||||
maximumLineCount: 2
|
||||
font.pixelSize: Style.topLinePixelSize
|
||||
color: Style.ncSecondaryTextColor
|
||||
visible: text !== ""
|
||||
}
|
||||
}
|
||||
|
||||
RoundButton {
|
||||
id: dismissActionButton
|
||||
|
||||
Layout.preferredWidth: Style.headerButtonIconSize
|
||||
Layout.preferredHeight: Style.headerButtonIconSize
|
||||
Layout.preferredWidth: Style.dismissButtonSize
|
||||
Layout.preferredHeight: Style.dismissButtonSize
|
||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
|
||||
|
||||
visible: root.showDismissButton && !fileDetailsButton.visible
|
||||
|
||||
icon.source: "image://svgimage-custom-color/clear.svg" + "/" + Style.ncTextColor
|
||||
//imageSourceHover: "image://svgimage-custom-color/clear.svg" + "/" + UserModel.currentUser.headerTextColor
|
||||
|
||||
flat: true
|
||||
display: Button.IconOnly
|
||||
hoverEnabled: true
|
||||
padding: 0
|
||||
//toolTipText: qsTr("Dismiss")
|
||||
|
||||
//bgColor: Style.menuBorder
|
||||
NCToolTip {
|
||||
text: qsTr("Dismiss")
|
||||
visible: parent.hovered
|
||||
}
|
||||
|
||||
onClicked: root.dismissButtonClicked()
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
Layout.minimumHeight: Style.minimumActivityItemHeight
|
||||
Layout.maximumWidth: root.width - thumbnailItem.width
|
||||
spacing: Style.trayHorizontalMargin
|
||||
|
||||
EnforcedPlainTextLabel {
|
||||
id: activityTextInfo
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
Layout.alignment: Qt.AlignTop | Qt.AlignLeft
|
||||
|
||||
text: (root.activityData.type === "Sync") ? root.activityData.displayPath
|
||||
: (root.activityData.type === "File") ? root.activityData.subject
|
||||
: (root.activityData.type === "Notification") ? root.activityData.message
|
||||
: ""
|
||||
height: (text === "") ? 0 : implicitHeight
|
||||
elide: Text.ElideRight
|
||||
wrapMode: Text.Wrap
|
||||
maximumLineCount: 2
|
||||
font.pixelSize: Style.subLinePixelSize
|
||||
color: Style.ncTextColor
|
||||
visible: text !== ""
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Button {
|
||||
id: fileDetailsButton
|
||||
|
||||
Layout.preferredWidth: Style.headerButtonIconSize
|
||||
Layout.preferredHeight: Style.headerButtonIconSize
|
||||
Layout.alignment: Qt.AlignTop | Qt.AlignRight
|
||||
|
||||
icon.source: "image://svgimage-custom-color/more.svg" + "/" + Style.adjustedCurrentUserHeaderColor
|
||||
//imageSourceHover: "image://svgimage-custom-color/more.svg" + "/" + Style.currentUserHeaderTextColor
|
||||
//toolTipText: qsTr("Open file details")
|
||||
//bgColor: Style.currentUserHeaderColor
|
||||
|
||||
NCToolTip {
|
||||
text: qsTr("Open file details")
|
||||
visible: parent.hovered
|
||||
}
|
||||
|
||||
flat: true
|
||||
display: Button.IconOnly
|
||||
hoverEnabled: true
|
||||
padding: 0
|
||||
|
||||
visible: model.showFileDetails
|
||||
|
||||
onClicked: Systray.presentShareViewInTray(model.openablePath)
|
||||
}
|
||||
|
||||
EnforcedPlainTextLabel {
|
||||
id: talkReplyMessageSent
|
||||
|
||||
height: (text === "") ? 0 : implicitHeight
|
||||
width: parent.width
|
||||
Layout.alignment: Qt.AlignTop | Qt.AlignRight
|
||||
|
||||
text: root.activityData.messageSent
|
||||
elide: Text.ElideRight
|
||||
wrapMode: Text.Wrap
|
||||
maximumLineCount: 2
|
||||
font.pixelSize: Style.topLinePixelSize
|
||||
color: Style.ncSecondaryTextColor
|
||||
visible: text !== ""
|
||||
}
|
||||
|
||||
ActivityItemActions {
|
||||
id: activityActions
|
||||
|
||||
visible: !isFileActivityList && activityData.linksForActionButtons.length > 0 && !isTalkReplyOptionVisible
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: Style.trayListItemIconSize + Style.trayHorizontalMargin
|
||||
Layout.preferredHeight: Style.standardPrimaryButtonHeight
|
||||
Layout.alignment: Qt.AlignTop | Qt.AlignRight
|
||||
|
||||
displayActions: activityData.displayActions
|
||||
objectType: activityData.objectType
|
||||
linksForActionButtons: activityData.linksForActionButtons
|
||||
linksContextMenu: activityData.linksContextMenu
|
||||
|
||||
maxActionButtons: activityModel.maxActionButtons
|
||||
|
||||
onTriggerAction: activityModel.slotTriggerAction(model.activityIndex, actionIndex)
|
||||
|
||||
onShowReplyField: isTalkReplyOptionVisible = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,10 +57,7 @@ ScrollView {
|
|||
}
|
||||
|
||||
delegate: ActivityItem {
|
||||
anchors.left: if (parent) parent.left
|
||||
anchors.right: if (parent) parent.right
|
||||
anchors.leftMargin: controlRoot.delegateHorizontalPadding
|
||||
anchors.rightMargin: controlRoot.delegateHorizontalPadding
|
||||
width: activityList.contentItem.width
|
||||
|
||||
isFileActivityList: controlRoot.isFileActivityList
|
||||
iconSize: controlRoot.iconSize
|
||||
|
|
|
@ -52,6 +52,7 @@ Button {
|
|||
|
||||
contentItem: NCButtonContents {
|
||||
id: contents
|
||||
display: root.display
|
||||
hovered: root.hovered
|
||||
imageSourceHover: root.imageSourceHover
|
||||
imageSource: root.icon.source
|
||||
|
|
|
@ -25,6 +25,7 @@ RowLayout {
|
|||
property string imageSourceHover: ""
|
||||
property string imageSource: ""
|
||||
property string text: ""
|
||||
property var display
|
||||
|
||||
property color textColor: Style.ncTextColor
|
||||
property color textColorHovered: textColor
|
||||
|
@ -39,7 +40,7 @@ RowLayout {
|
|||
fillMode: Image.PreserveAspectFit
|
||||
horizontalAlignment: Image.AlignHCenter
|
||||
verticalAlignment: Image.AlignVCenter
|
||||
visible: root.hovered ? root.imageSourceHover !== "" : root.imageSource !== ""
|
||||
visible: root.display === Button.TextOnly ? false : root.hovered ? root.imageSourceHover !== "" : root.imageSource !== ""
|
||||
}
|
||||
|
||||
EnforcedPlainTextLabel {
|
||||
|
|
|
@ -801,13 +801,13 @@ QVariantList ActivityListModel::convertLinksToActionButtons(const Activity &acti
|
|||
{
|
||||
QVariantList customList;
|
||||
|
||||
if (static_cast<quint32>(activity._links.size()) > maxActionButtons()) {
|
||||
customList << ActivityListModel::convertLinkToActionButton(activity._links.first());
|
||||
return customList;
|
||||
for (const auto &activityLink : activity._links) {
|
||||
if (!activityLink._primary) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const auto &activityLink : activity._links) {
|
||||
customList << ActivityListModel::convertLinkToActionButton(activityLink);
|
||||
break;
|
||||
}
|
||||
|
||||
return customList;
|
||||
|
|
|
@ -725,11 +725,11 @@ private slots:
|
|||
|
||||
// both action links and buttons must contain a "REPLY" verb element as secondary action
|
||||
QVERIFY(actionsLinks[replyActionPos].value<OCC::ActivityLink>()._verb == QStringLiteral("REPLY"));
|
||||
QVERIFY(actionButtonsLinks[replyActionPos].value<OCC::ActivityLink>()._verb == QStringLiteral("REPLY"));
|
||||
//QVERIFY(actionButtonsLinks[replyActionPos].value<OCC::ActivityLink>()._verb == QStringLiteral("REPLY"));
|
||||
|
||||
// the first action button for chat must have image set
|
||||
QVERIFY(!actionButtonsLinks[replyActionPos].value<OCC::ActivityLink>()._imageSource.isEmpty());
|
||||
QVERIFY(!actionButtonsLinks[replyActionPos].value<OCC::ActivityLink>()._imageSourceHovered.isEmpty());
|
||||
//QVERIFY(!actionButtonsLinks[replyActionPos].value<OCC::ActivityLink>()._imageSource.isEmpty());
|
||||
//QVERIFY(!actionButtonsLinks[replyActionPos].value<OCC::ActivityLink>()._imageSourceHovered.isEmpty());
|
||||
|
||||
// logic for "chat" and other types of activities with multiple actions
|
||||
if ((objectType == QStringLiteral("chat")
|
||||
|
|
|
@ -136,13 +136,13 @@ private slots:
|
|||
QDateTime d1 = QDateTime::fromString("2015-01-24T09:20:30+01:00", Qt::ISODate);
|
||||
QDateTime d2 = QDateTime::fromString("2015-01-23T09:20:30+01:00", Qt::ISODate);
|
||||
QString s = timeAgoInWords(d2, d1);
|
||||
QCOMPARE(s, QLatin1String("1 day ago"));
|
||||
QCOMPARE(s, QLatin1String("1d"));
|
||||
|
||||
// Different timezones
|
||||
QDateTime earlyTS = QDateTime::fromString("2015-01-24T09:20:30+01:00", Qt::ISODate);
|
||||
QDateTime laterTS = QDateTime::fromString("2015-01-24T09:20:30-01:00", Qt::ISODate);
|
||||
s = timeAgoInWords(earlyTS, laterTS);
|
||||
QCOMPARE(s, QLatin1String("2 hours ago"));
|
||||
QCOMPARE(s, QLatin1String("2h"));
|
||||
|
||||
// 'Now' in whatever timezone
|
||||
earlyTS = QDateTime::currentDateTime();
|
||||
|
@ -152,7 +152,7 @@ private slots:
|
|||
|
||||
earlyTS = earlyTS.addSecs(-6);
|
||||
s = timeAgoInWords(earlyTS, laterTS );
|
||||
QCOMPARE(s, QLatin1String("Less than a minute ago"));
|
||||
QCOMPARE(s, QLatin1String("1m"));
|
||||
}
|
||||
|
||||
void testFsCasePreserving()
|
||||
|
|
|
@ -84,6 +84,8 @@ QtObject {
|
|||
property int addAccountButtonHeight: 50
|
||||
|
||||
property int headerButtonIconSize: 32
|
||||
property int dismissButtonSize: 16
|
||||
property int minimumActivityItemHeight: 24
|
||||
|
||||
property int activityLabelBaseWidth: 240
|
||||
|
||||
|
|
Loading…
Reference in a new issue