Fix focus and simplify popup-opener menu items

Introduce a HmenuItemPopupSpawner component that takes care of reacting
to onTriggered signals and calling the utils.makePopup() function.

The combination of this new component used in HMenu to open a HPopup
now correctly takes and restore focus to the right element when closed.
This commit is contained in:
miruka 2019-12-20 10:29:45 -04:00
parent d9b7118f45
commit 9bd739a0db
9 changed files with 85 additions and 58 deletions

10
TODO.md
View File

@ -48,13 +48,13 @@
## Issues ## Issues
- invisible uploaded mxc images? - `EventImage`s for `m.image` sometimes appear broken, can be made normal
- first undecryptable message by switching to another room and coming back
- Join button 502 - First sent message in E2E room is sometimes undecryptable
- Leave box button focus - Handle matrix errors for accept/decline invite buttons and other
- Pause upload, switch to other room, then come back → wrong state displayed
- Pausing uploads doesn't work well, servers end up dropping the connection - Pausing uploads doesn't work well, servers end up dropping the connection
- Pause upload, switch to other room, then come back, wrong state displayed
- In the "Leave me" room, "join > Hi > left" aren't combined - In the "Leave me" room, "join > Hi > left" aren't combined
- When selecting text and scrolling up, selection stops working after a while - When selecting text and scrolling up, selection stops working after a while

View File

@ -25,9 +25,17 @@ Menu {
border.width: theme.controls.menu.borderWidth border.width: theme.controls.menu.borderWidth
} }
onAboutToShow: previouslyFocused = window.activeFocusItem onAboutToShow: {
onClosed: if (previouslyFocused) previouslyFocused.forceActiveFocus() previouslyFocused = window.activeFocusItem
focusOnClosed = Qt.binding(() => previouslyFocused)
}
onClosed: if (focusOnClosed) focusOnClosed.forceActiveFocus()
property var previouslyFocused: null property var previouslyFocused: null
// MenuItems that open popups (or other elements taking focus when opened)
// should set this to null. It will be reset to previouslyFocus when
// the Menu is closed and opened again.
property Item focusOnClosed: previouslyFocused
} }

View File

@ -12,11 +12,6 @@ MenuItem {
bottomPadding: topPadding bottomPadding: topPadding
height: visible ? implicitHeight : 0 height: visible ? implicitHeight : 0
readonly property alias iconItem: contentItem.icon
readonly property alias label: contentItem.label
background: HButtonBackground { background: HButtonBackground {
button: menuItem button: menuItem
buttonTheme: theme.controls.menuItem buttonTheme: theme.controls.menuItem
@ -28,4 +23,8 @@ MenuItem {
buttonTheme: theme.controls.menuItem buttonTheme: theme.controls.menuItem
label.horizontalAlignment: Label.AlignLeft label.horizontalAlignment: Label.AlignLeft
} }
readonly property alias iconItem: contentItem.icon
readonly property alias label: contentItem.label
} }

View File

@ -0,0 +1,27 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
import QtQuick 2.12
import QtQuick.Controls 2.12
HMenuItem {
onTriggered: {
print( parent.parent.parent)
menu.focusOnClosed = null
utils.makePopup(
popup,
popupParent,
utils.objectUpdate(
{ focusOnClosed: menu.previouslyFocused }, properties,
),
null,
autoDestruct,
)
}
property var popup // url or HPopup Component
property QtObject popupParent: window
property bool autoDestruct: true
property var properties: ({})
}

View File

@ -24,10 +24,11 @@ Popup {
} }
onAboutToShow: previouslyFocused = window.activeFocusItem onAboutToShow: previouslyFocused = window.activeFocusItem
onClosed: if (previouslyFocused) previouslyFocused.forceActiveFocus() onClosed: if (focusOnClosed) focusOnClosed.forceActiveFocus()
property var previouslyFocused: null property var previouslyFocused: null
property Item focusOnClosed: previouslyFocused
readonly property int maximumPreferredWidth: readonly property int maximumPreferredWidth:
window.width - leftMargin - rightMargin - leftInset - rightInset window.width - leftMargin - rightMargin - leftInset - rightInset

View File

@ -110,15 +110,13 @@ HTileDelegate {
onTriggered: Clipboard.text = model.data.user_id onTriggered: Clipboard.text = model.data.user_id
} }
HMenuItem { HMenuItemPopupSpawner {
icon.name: "sign-out" icon.name: "sign-out"
icon.color: theme.colors.negativeBackground icon.color: theme.colors.negativeBackground
text: qsTr("Sign out") text: qsTr("Sign out")
onTriggered: utils.makePopup(
"Popups/SignOutPopup.qml", popup: "Popups/SignOutPopup.qml"
window, properties: { "userId": model.data.user_id }
{ "userId": model.data.user_id },
)
} }
} }
} }

View File

@ -91,22 +91,19 @@ HTileDelegate {
} }
contextMenu: HMenu { contextMenu: HMenu {
HMenuItem { HMenuItemPopupSpawner {
visible: joined visible: joined
enabled: model.data.can_invite enabled: model.data.can_invite
icon.name: "room-send-invite" icon.name: "room-send-invite"
text: qsTr("Invite members") text: qsTr("Invite members")
onTriggered: utils.makePopup( popup: "Popups/InviteToRoomPopup.qml"
"Popups/InviteToRoomPopup.qml", properties: ({
window, userId: model.user_id,
{ roomId: model.data.room_id,
userId: model.user_id, roomName: model.data.display_name,
roomId: model.data.room_id, invitingAllowed: Qt.binding(() => model.data.can_invite)
roomName: model.data.display_name, })
invitingAllowed: Qt.binding(() => model.data.can_invite)
}
)
} }
HMenuItem { HMenuItem {
@ -129,39 +126,32 @@ HTileDelegate {
) )
} }
HMenuItem { HMenuItemPopupSpawner {
visible: invited || joined visible: invited || joined
icon.name: invited ? "invite-decline" : "room-leave" icon.name: invited ? "invite-decline" : "room-leave"
icon.color: theme.colors.negativeBackground icon.color: theme.colors.negativeBackground
text: invited ? qsTr("Decline invite") : qsTr("Leave") text: invited ? qsTr("Decline invite") : qsTr("Leave")
onTriggered: utils.makePopup( popup: "Popups/LeaveRoomPopup.qml"
"Popups/LeaveRoomPopup.qml", properties: ({
window, userId: model.user_id,
{ roomId: model.data.room_id,
userId: model.user_id, roomName: model.data.display_name,
roomId: model.data.room_id, })
roomName: model.data.display_name,
}
)
} }
HMenuItem { HMenuItemPopupSpawner {
icon.name: "room-forget" icon.name: "room-forget"
icon.color: theme.colors.negativeBackground icon.color: theme.colors.negativeBackground
text: qsTr("Forget") text: qsTr("Forget")
onTriggered: utils.makePopup( popup: "Popups/ForgetRoomPopup.qml"
"Popups/ForgetRoomPopup.qml", autoDestruct: false
window, properties: ({
{ userId: model.user_id,
userId: model.user_id, roomId: model.data.room_id,
roomId: model.data.room_id, roomName: model.data.display_name,
roomName: model.data.display_name, })
},
null,
false,
)
} }
} }
} }

View File

@ -170,14 +170,13 @@ HColumnLayout {
Clipboard.text = selectableLabelContainer.joinedSelection Clipboard.text = selectableLabelContainer.joinedSelection
} }
HMenuItem { HMenuItemPopupSpawner {
icon.name: "clear-messages" icon.name: "clear-messages"
text: qsTr("Clear messages") text: qsTr("Clear messages")
onTriggered: utils.makePopup(
"Popups/ClearMessagesPopup.qml", popup: "Popups/ClearMessagesPopup.qml"
chat, popupParent: chat
{userId: chat.userId, roomId: chat.roomId}, properties: ({userId: chat.userId, roomId: chat.roomId})
)
} }
} }
} }

View File

@ -68,6 +68,11 @@ QtObject {
} }
function objectUpdate(current, update) {
return Object.assign({}, current, update)
}
function objectUpdateRecursive(current, update) { function objectUpdateRecursive(current, update) {
for (const key of Object.keys(update)) { for (const key of Object.keys(update)) {
if ((key in current) && typeof(current[key]) === "object" && if ((key in current) && typeof(current[key]) === "object" &&