diff --git a/panels/notification/center/NormalNotify.qml b/panels/notification/center/NormalNotify.qml index e05a4c568..d2cfe8c1a 100644 --- a/panels/notification/center/NormalNotify.qml +++ b/panels/notification/center/NormalNotify.qml @@ -14,29 +14,6 @@ NotifyItem { implicitWidth: impl.implicitWidth implicitHeight: impl.implicitHeight - property var removedCallback - - states: [ - State { - name: "removing" - PropertyChanges { target: root; x: root.width; opacity: 0} - } - ] - - transitions: Transition { - to: "removing" - ParallelAnimation { - NumberAnimation { properties: "x"; duration: 300; easing.type: Easing.Linear } - NumberAnimation { properties: "opacity"; duration: 300; easing.type: Easing.Linear } - } - onRunningChanged: { - if (!running && root.removedCallback) { - root.removedCallback() - root.removedCallback = undefined - } - } - } - Control { id: impl anchors.fill: parent @@ -54,18 +31,13 @@ NotifyItem { strongInteractive: root.strongInteractive contentIcon: root.contentIcon contentRowCount: root.contentRowCount + indexInGroup: root.indexInGroup onRemove: function () { - root.removedCallback = function () { - root.remove() - } - root.state = "removing" + root.remove() } onDismiss: function () { - root.removedCallback = function () { - root.dismiss() - } - root.state = "removing" + root.dismiss() } onActionInvoked: function (actionId) { root.actionInvoked(actionId) diff --git a/panels/notification/center/NotifyCenter.qml b/panels/notification/center/NotifyCenter.qml index ee5f9221b..fb161d5dd 100644 --- a/panels/notification/center/NotifyCenter.qml +++ b/panels/notification/center/NotifyCenter.qml @@ -15,6 +15,7 @@ FocusScope { palette: DTK.palette property alias model: notifyModel + property alias viewPanelShown: view.viewPanelShown property int maxViewHeight: 400 property int stagingViewCount: 0 diff --git a/panels/notification/center/NotifyView.qml b/panels/notification/center/NotifyView.qml index 613740e57..3ec145556 100644 --- a/panels/notification/center/NotifyView.qml +++ b/panels/notification/center/NotifyView.qml @@ -6,6 +6,7 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts import org.deepin.dtk 1.0 +import org.deepin.ds import org.deepin.ds.notificationcenter Control { @@ -13,6 +14,7 @@ Control { focus: true required property NotifyModel notifyModel + property alias viewPanelShown: view.panelShown readonly property real viewHeight: view.contentHeight readonly property int viewCount: view.count @@ -28,6 +30,7 @@ Control { // activeFocusOnTab: true ScrollBar.vertical: ScrollBar { } property int nextIndex: -1 + property bool panelShown: false onNextIndexChanged: { if (nextIndex >= 0 && count > 0) { @@ -52,26 +55,112 @@ Control { notifySetting.toggle(); } } - // remove: Transition { - // ParallelAnimation { - // NumberAnimation { properties: "y"; duration: 300 } - // } - // } - // add: Transition { - // ParallelAnimation { - // NumberAnimation { properties: "y"; duration: 300 } - // } - // } - // addDisplaced: Transition { - // ParallelAnimation { - // NumberAnimation { properties: "y"; duration: 300 } - // } - // } - // moveDisplaced: Transition { - // ParallelAnimation { - // NumberAnimation { properties: "y"; duration: 300 } - // } - // } + add: Transition { + id: addTrans + enabled: view.panelShown + + NumberAnimation { + properties: "y" + from: { + if (addTrans.ViewTransition.item.objectName.startsWith("overlap-")) { + // 24: group notify overlap height + return addTrans.ViewTransition.destination.y + view.spacing + 24 + } else if (addTrans.ViewTransition.item.indexInGroup === 0) { + return addTrans.ViewTransition.destination.y - view.spacing - 24 + } else { + return addTrans.ViewTransition.destination.y + } + } + duration: 400 + easing.type: Easing.OutQuart + } + + NumberAnimation { + property: "opacity"; + from: { + if (addTrans.ViewTransition.item.objectName.startsWith("overlap-")) { + return 0 + } else if (addTrans.ViewTransition.item.indexInGroup === 0) { + return 1 + } else { + return 0 + } + } + to: 1 + duration: { + if (addTrans.ViewTransition.item.objectName.startsWith("overlap-")) { + return 0 + } else if (addTrans.ViewTransition.item.indexInGroup === 0) { + return 100 + } else { + return 600 + } + } + easing.type: Easing.OutExpo + } + } + + remove: Transition { + id: removeTrans + NumberAnimation { + properties: "y" + to: { + if (removeTrans.ViewTransition.item.objectName.startsWith("overlap-")) { + return removeTrans.ViewTransition.destination.y + view.spacing + 24 + } else if (removeTrans.ViewTransition.item.indexInGroup === 1) { + return removeTrans.ViewTransition.destination.y - view.spacing - 24 + } else if (removeTrans.ViewTransition.item.indexInGroup === 2) { + return removeTrans.ViewTransition.destination.y - view.spacing - 24 + } else { + return removeTrans.ViewTransition.destination.y + } + } + duration: 400 + easing.type: Easing.OutQuart + } + + NumberAnimation { + property: "scale"; + from: 1 + to: { + if (removeTrans.ViewTransition.item.indexInGroup === 1) { + return 0.9 + } else if (removeTrans.ViewTransition.item.indexInGroup === 2) { + return 0.9 + } else { + return 1 + } + } + duration: 600 + easing.type: Easing.OutExpo + } + + NumberAnimation { + property: "opacity"; + to: 0 + duration: { + if (removeTrans.ViewTransition.item.indexInGroup === 0) { + return 100 + } else if (removeTrans.ViewTransition.item.objectName.startsWith("overlap-")) { + return 100 + } else { + return 600 + } + } + easing.type: Easing.OutExpo + } + } + + addDisplaced: Transition { + id: addDisplacedTrans + NumberAnimation { property: "y"; duration: 400; easing.type: Easing.OutQuart} + NumberAnimation { property: "opacity"; to: 1.0; duration: 600; easing.type: Easing.OutExpo} + } + + removeDisplaced: Transition { + id: removeDisplacedTrans + NumberAnimation { properties: "y"; duration: 400; easing.type: Easing.OutQuart} + } } background: BoundingRectangle {} diff --git a/panels/notification/center/NotifyViewDelegate.qml b/panels/notification/center/NotifyViewDelegate.qml index 182b41027..fe69b42d0 100644 --- a/panels/notification/center/NotifyViewDelegate.qml +++ b/panels/notification/center/NotifyViewDelegate.qml @@ -26,6 +26,7 @@ DelegateChooser { width: NotifyStyle.contentItem.width appName: model.appName activeFocusOnTab: true + z: index Loader { anchors.fill: parent @@ -63,6 +64,7 @@ DelegateChooser { objectName: "normal-" + model.appName width: NotifyStyle.contentItem.width activeFocusOnTab: true + z: index appName: model.appName iconName: model.iconName @@ -74,6 +76,7 @@ DelegateChooser { contentIcon: model.contentIcon contentRowCount: model.contentRowCount defaultAction: model.defaultAction + indexInGroup: model.indexInGroup Loader { anchors.fill: parent @@ -126,6 +129,7 @@ DelegateChooser { objectName: "overlap-" + model.appName width: NotifyStyle.contentItem.width activeFocusOnTab: true + z: index count: model.overlapCount appName: model.appName diff --git a/panels/notification/center/OverlapNotify.qml b/panels/notification/center/OverlapNotify.qml index d57693af5..de0806f7d 100644 --- a/panels/notification/center/OverlapNotify.qml +++ b/panels/notification/center/OverlapNotify.qml @@ -65,17 +65,12 @@ NotifyItem { contentIcon: root.contentIcon contentRowCount: root.contentRowCount enableDismissed: root.enableDismissed + indexInGroup: root.indexInGroup onRemove: function () { - root.removedCallback = function () { - root.remove() - } - root.state = "removing" + root.remove() } onDismiss: function () { - root.removedCallback = function () { - root.dismiss() - } - root.state = "removing" + root.dismiss() } onActionInvoked: function (actionId) { root.actionInvoked(actionId) @@ -84,6 +79,7 @@ NotifyItem { OverlapIndicator { id: indicator + enableAnimation: root.ListView.view.panelShown anchors { bottom: parent.bottom left: parent.left diff --git a/panels/notification/center/notifyitem.h b/panels/notification/center/notifyitem.h index c97c27d0d..32c866a0e 100644 --- a/panels/notification/center/notifyitem.h +++ b/panels/notification/center/notifyitem.h @@ -41,6 +41,9 @@ class AppNotifyItem : public QObject void updateActions(); void updateStrongInteractive(); + int indexInGroup() const { return m_indexInGroup; } + void setIndexInGroup(int index) { m_indexInGroup = index; } + void refresh(); bool pinned() const; @@ -54,6 +57,7 @@ class AppNotifyItem : public QObject NotifyEntity m_entity; bool m_pinned = false; bool m_strongInteractive = false; + int m_indexInGroup = -1; }; class BubbleNotifyItem : public AppNotifyItem diff --git a/panels/notification/center/notifymodel.cpp b/panels/notification/center/notifymodel.cpp index f721e4e50..5ea4ea34a 100644 --- a/panels/notification/center/notifymodel.cpp +++ b/panels/notification/center/notifymodel.cpp @@ -77,6 +77,7 @@ void NotifyModel::expandApp(int row) for (int i = 0; i < notifies.size(); i++) { auto item = notifies[i]; m_appNotifies.insert(start + i, item); + item->setIndexInGroup(i); } endInsertRows(); } @@ -724,6 +725,8 @@ QVariant NotifyModel::data(const QModelIndex &index, int role) const } } else if (role == NotifyRole::NotifyContentRowCount) { return NotifySetting::instance()->contentRowCount(); + } else if (role == NotifyRole::NotifyIndexInGroup) { + return notify->indexInGroup(); } return QVariant::fromValue(notify); } @@ -778,7 +781,8 @@ QHash NotifyModel::roleNames() const {NotifyStrongInteractive, "strongInteractive"}, {NotifyContentIcon, "contentIcon"}, {NotifyOverlapCount, "overlapCount"}, - {NotifyContentRowCount, "contentRowCount"}}; + {NotifyContentRowCount, "contentRowCount"}, + {NotifyIndexInGroup, "indexInGroup"}}; return roles; } diff --git a/panels/notification/center/notifymodel.h b/panels/notification/center/notifymodel.h index 0127a9484..6e2960cce 100644 --- a/panels/notification/center/notifymodel.h +++ b/panels/notification/center/notifymodel.h @@ -37,7 +37,8 @@ class NotifyModel : public QAbstractListModel NotifyStrongInteractive, NotifyContentIcon, NotifyOverlapCount, - NotifyContentRowCount + NotifyContentRowCount, + NotifyIndexInGroup }; NotifyModel(QObject *parent = nullptr); diff --git a/panels/notification/center/package/main.qml b/panels/notification/center/package/main.qml index adb63f6a6..c63f4790c 100644 --- a/panels/notification/center/package/main.qml +++ b/panels/notification/center/package/main.qml @@ -106,8 +106,12 @@ Window { function onVisibleChanged() { if (Panel.visible) { notifyStaging.model.open() + DS.singleShot(100, function() { + notifyCenter.viewPanelShown = true + }) } else { notifyStaging.model.close() + notifyCenter.viewPanelShown = false } } } @@ -127,8 +131,12 @@ Window { function onVisibleChanged() { if (Panel.visible) { notifyCenter.model.open() + DS.singleShot(100, function() { + notifyCenter.viewPanelShown = true + }) } else { notifyCenter.model.close() + notifyCenter.viewPanelShown = false } } } diff --git a/panels/notification/plugin/NotifyItem.qml b/panels/notification/plugin/NotifyItem.qml index 7bbc5ca4e..189e2650b 100644 --- a/panels/notification/plugin/NotifyItem.qml +++ b/panels/notification/plugin/NotifyItem.qml @@ -32,6 +32,7 @@ FocusScope { property bool strongInteractive: false property string contentIcon: "deepin-editor" property int contentRowCount: 6 + property int indexInGroup: -1 signal remove() signal dismiss() diff --git a/panels/notification/plugin/NotifyItemContent.qml b/panels/notification/plugin/NotifyItemContent.qml index 1435af1a1..e9f7fb4aa 100644 --- a/panels/notification/plugin/NotifyItemContent.qml +++ b/panels/notification/plugin/NotifyItemContent.qml @@ -133,6 +133,7 @@ NotifyItem { } DciIcon { + id: appIcon name: root.iconName !== "" ? root.iconName : "application-x-desktop" sourceSize: Qt.size(24, 24) Layout.alignment: Qt.AlignLeft | Qt.AlignTop @@ -143,6 +144,7 @@ NotifyItem { } ColumnLayout { + id: contentLayout spacing: 0 Layout.alignment: Qt.AlignLeft | Qt.AlignTop Layout.rightMargin: 10 @@ -200,12 +202,18 @@ NotifyItem { } RowLayout { + id: bodyRow Layout.fillWidth: true Layout.alignment: Qt.AlignLeft | Qt.AlignTop Text { id: bodyText Layout.alignment: Qt.AlignLeft | Qt.AlignTop - Layout.fillWidth: true + // text 宽度若让Layout通过implicitWidth计算会导致ListView的add动画出现位置错误,故这里手动计算Text的宽度 + Layout.preferredWidth: NotifyStyle.contentItem.width - appIcon.width + - appIcon.Layout.leftMargin - appIcon.Layout.rightMargin + - contentLayout.Layout.rightMargin - contentLayout.Layout.leftMargin + - (contentIconLoader.active ? (contentIconLoader.width + 1) : 0) + - bodyRow.spacing * bodyRow.children.length - 1 visible: text !== "" text: root.content maximumLineCount: root.contentRowCount @@ -228,6 +236,7 @@ NotifyItem { } Loader { + id: contentIconLoader Layout.maximumWidth: 106 Layout.maximumHeight: 106 Layout.minimumWidth: 16 diff --git a/panels/notification/plugin/OverlapIndicator.qml b/panels/notification/plugin/OverlapIndicator.qml index 988b13536..fb96afafd 100644 --- a/panels/notification/plugin/OverlapIndicator.qml +++ b/panels/notification/plugin/OverlapIndicator.qml @@ -14,6 +14,7 @@ Item { property int radius: 12 property int overlapHeight: 8 property bool revert: false + property bool enableAnimation: false implicitHeight: layout.height implicitWidth: 360 @@ -40,6 +41,34 @@ Item { topMargin: revert ? undefined : -(height - overlapHeight) bottomMargin: revert ? -(height - overlapHeight) : undefined } + opacity: 0 + + Component.onCompleted: { + if (root.enableAnimation) { + fadeInAnimation.start() + } else { + opacity = 1 + } + } + + SequentialAnimation { + id: fadeInAnimation + + PauseAnimation { + duration: realIndex * 100 + } + + ParallelAnimation { + NumberAnimation { + target: background + property: "opacity" + from: 0 + to: 1 + duration: 300 + easing.type: Easing.OutQuad + } + } + } } } }