Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
21 changes: 21 additions & 0 deletions panels/notification/center/GroupNotify.qml
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,30 @@ NotifyItem {
return true
}

// Focus the last button for Shift+Tab navigation into group
function focusLastButton() {
groupClearBtn.forceActiveFocus()
return true
}

Control {
id: impl
anchors.fill: parent
focus: true

Keys.onTabPressed: function(event) {
if (root.focusFirstButton()) {
event.accepted = true
} else {
root.gotoNextItem()
event.accepted = true
}
}

Keys.onBacktabPressed: function(event) {
root.gotoPrevItem()
event.accepted = true
}

contentItem: RowLayout {
NotifyHeaderTitleText {
Expand Down
26 changes: 25 additions & 1 deletion panels/notification/center/NormalNotify.qml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ NotifyItem {
id: root
implicitWidth: impl.implicitWidth
implicitHeight: impl.implicitHeight
property bool shouldShowClose: false // True when item gets focus from keyboard navigation

signal gotoNextItem()
signal gotoPrevItem()
Expand All @@ -21,9 +22,31 @@ NotifyItem {
return notifyContent.focusFirstButton()
}

function focusLastButton() {
return notifyContent.focusLastButton()
}

Control {
id: impl
anchors.fill: parent
focus: true

Keys.onTabPressed: function(event) {
// Mark that this item got focus from Tab navigation
root.shouldShowClose = true
if (notifyContent.focusFirstButton()) {
event.accepted = true
} else {
root.gotoNextItem()
event.accepted = true
}
}

Keys.onBacktabPressed: function(event) {
root.shouldShowClose = true
root.gotoPrevItem()
event.accepted = true
}

contentItem: NotifyItemContent {
id: notifyContent
Expand All @@ -35,7 +58,8 @@ NotifyItem {
date: root.date
actions: root.actions
defaultAction: root.defaultAction
parentHovered: impl.hovered || root.activeFocus
// Show close button when: mouse hovers, or item has focus from keyboard navigation
parentHovered: impl.hovered || (root.activeFocus && root.shouldShowClose)
strongInteractive: root.strongInteractive
contentIcon: root.contentIcon
contentRowCount: root.contentRowCount
Expand Down
94 changes: 22 additions & 72 deletions panels/notification/center/NotifyViewDelegate.qml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@ DelegateChooser {
view.positionViewAtIndex(currentIndex + 1, ListView.Contain)
Qt.callLater(function() {
let nextItem = view.itemAtIndex(currentIndex + 1)
if (nextItem && nextItem.enabled) nextItem.forceActiveFocus()
if (nextItem && nextItem.enabled) {
// Focus on the item itself first, not directly to buttons
nextItem.forceActiveFocus()
}
})
} else {
view.gotoHeaderFirst()
Expand All @@ -39,7 +42,10 @@ DelegateChooser {
view.positionViewAtIndex(currentIndex - 1, ListView.Contain)
Qt.callLater(function() {
let prevItem = view.itemAtIndex(currentIndex - 1)
if (prevItem && prevItem.enabled) prevItem.forceActiveFocus()
if (prevItem && prevItem.enabled) {
// Focus on the item itself first, not directly to buttons
prevItem.forceActiveFocus()
}
})
} else {
view.gotoHeaderLast()
Expand All @@ -56,27 +62,8 @@ DelegateChooser {
activeFocusOnTab: false
z: index

Keys.onTabPressed: function(event) {
groupNotify.focusFirstButton()
event.accepted = true
}
Keys.onBacktabPressed: function(event) {
root.navigateToPrevItem(index)
event.accepted = true
}

onGotoNextItem: root.navigateToNextItem(index)
onGotoPrevItem: groupNotify.focusFirstButton()

Loader {
anchors.fill: parent
active: groupNotify.activeFocus && NotifyAccessor.debugging

sourceComponent: FocusBoxBorder {
radius: groupNotify.radius
color: groupNotify.palette.highlight
}
}
onGotoPrevItem: root.navigateToPrevItem(index)

onCollapse: function () {
console.log("collapse group", model.appName)
Expand Down Expand Up @@ -108,23 +95,8 @@ DelegateChooser {
activeFocusOnTab: false
z: index

Keys.onTabPressed: function(event) {
if (normalNotify.focusFirstButton()) {
event.accepted = true
return
}
Qt.callLater(function() {
if (normalNotify.focusFirstButton()) return
root.navigateToNextItem(index)
})
event.accepted = true
}
Keys.onBacktabPressed: function(event) {
root.navigateToPrevItem(index)
event.accepted = true
}
onGotoNextItem: root.navigateToNextItem(index)
onGotoPrevItem: normalNotify.forceActiveFocus()
onGotoPrevItem: root.navigateToPrevItem(index)

appName: model.appName
iconName: model.iconName
Expand All @@ -138,16 +110,6 @@ DelegateChooser {
defaultAction: model.defaultAction
indexInGroup: model.indexInGroup

Loader {
anchors.fill: parent
active: normalNotify.activeFocus && NotifyAccessor.debugging

sourceComponent: FocusBoxBorder {
radius: normalNotify.radius
color: normalNotify.palette.highlight
}
}

TapHandler {
acceptedButtons: Qt.RightButton
onTapped: function (eventPoint, button) {
Expand Down Expand Up @@ -191,23 +153,8 @@ DelegateChooser {
activeFocusOnTab: false
z: index

Keys.onTabPressed: function(event) {
if (overlapNotify.focusFirstButton()) {
event.accepted = true
return
}
Qt.callLater(function() {
if (overlapNotify.focusFirstButton()) return
root.navigateToNextItem(index)
})
event.accepted = true
}
Keys.onBacktabPressed: function(event) {
root.navigateToPrevItem(index)
event.accepted = true
}
onGotoNextItem: root.navigateToNextItem(index)
onGotoPrevItem: overlapNotify.forceActiveFocus()
onGotoPrevItem: root.navigateToPrevItem(index)

count: model.overlapCount
appName: model.appName
Expand All @@ -221,15 +168,23 @@ DelegateChooser {
contentRowCount: model.contentRowCount
enableDismissed: false
notifyContent.clearButton: AnimationSettingButton {
id: clearBtn
icon.name: "clean-alone"
text: qsTr("Clean All")
activeFocusOnTab: false
focusBorderVisible: activeFocus
Keys.onTabPressed: function(event) {
// Try to focus first action button
if (overlapNotify.focusFirstButton()) {
event.accepted = true
return
}
// No enabled action buttons, go to next item
overlapNotify.gotoNextItem()
event.accepted = true
}
Keys.onBacktabPressed: function(event) {
// Shift+Tab: go back to previous item (clear button is first in tab order)
overlapNotify.gotoPrevItem()
event.accepted = true
}
Expand All @@ -238,14 +193,9 @@ DelegateChooser {
}
}

Loader {
anchors.fill: parent
active: overlapNotify.activeFocus && NotifyAccessor.debugging

sourceComponent: FocusBoxBorder {
radius: overlapNotify.overlapItemRadius
color: overlapNotify.palette.highlight
}
Component.onCompleted: {
// Pass clear button reference to OverlapNotify
overlapNotify.clearButton = clearBtn
}

TapHandler {
Expand Down
47 changes: 43 additions & 4 deletions panels/notification/center/OverlapNotify.qml
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,37 @@ NotifyItem {
property int count: 1
readonly property int overlapItemRadius: 12
property bool enableDismissed: true
property bool shouldShowClose: false // True when item gets focus from keyboard navigation
property var removedCallback
property alias notifyContent: notifyContent

signal expand()
signal gotoNextItem()
signal gotoPrevItem()

property var clearButton: null // Reference to the externally defined clear button

function focusFirstButton() {
return notifyContent.focusFirstButton()
// Focus clear button first, then action buttons
if (clearButton && clearButton.enabled && clearButton.visible) {
clearButton.forceActiveFocus()
return true
}
// Try action buttons (skip clear button to avoid loop)
return notifyContent.focusFirstActionOnly()
}

function focusLastButton() {
// Focus last action button, then clear button
if (notifyContent.focusLastButton()) {
return true
}
// Try clear button
if (clearButton && clearButton.enabled && clearButton.visible) {
clearButton.forceActiveFocus()
return true
}
return false
}

states: [
Expand All @@ -52,6 +74,23 @@ NotifyItem {
Control {
id: impl
anchors.fill: parent
focus: true

Keys.onTabPressed: function(event) {
root.shouldShowClose = true
if (notifyContent.focusFirstButton()) {
event.accepted = true
} else {
root.gotoNextItem()
event.accepted = true
}
}

Keys.onBacktabPressed: function(event) {
root.shouldShowClose = true
root.gotoPrevItem()
event.accepted = true
}

contentItem: Item {
width: parent.width
Expand All @@ -66,13 +105,13 @@ NotifyItem {
date: root.date
actions: root.actions
defaultAction: root.defaultAction
// Don't override closeVisible - use parentHovered to pass external hover/focus state
parentHovered: impl.hovered || root.activeFocus
// Show close button when: mouse hovers, or item has focus from keyboard navigation
parentHovered: impl.hovered || (root.activeFocus && root.shouldShowClose)
strongInteractive: root.strongInteractive
contentIcon: root.contentIcon
contentRowCount: root.contentRowCount
enableDismissed: root.enableDismissed
indexInGroup: root.indexInGroup
enableDismissed: root.enableDismissed
onRemove: function () {
root.remove()
}
Expand Down
Loading