Improve account status msg field & add history

- Up to 5 previously set status are now shown under the field
  for quick access; the history is shared between accounts

- When focusing the field, the text gets auto-selected since most of the
  time we want to set a totally different status, not edit the current one

- Typing in the field will autosuggest any matching history entry

- Keyboard focus now skips the "apply" button, since we can just hit
  enter in the field
This commit is contained in:
miruka 2021-04-16 11:49:51 -04:00
parent 67edd63c5a
commit 3402a1d5f8
3 changed files with 94 additions and 22 deletions

View File

@ -8,7 +8,7 @@ import Clipboard 0.1
import "../Base" import "../Base"
HMenu { HMenu {
id: accountMenu id: root
property string userId property string userId
property string presence property string presence
@ -20,32 +20,69 @@ HMenu {
py.callClientCoro(userId, "set_presence", [presence, statusMsg]) py.callClientCoro(userId, "set_presence", [presence, statusMsg])
} }
onOpened: statusText.forceActiveFocus() function statusFieldApply(newStatus=null) {
if (newStatus === null) newStatus = statusField.editText.trim()
if (newStatus) {
const existing = statusRepeater.items.indexOf(newStatus)
if (existing !== -1) statusRepeater.items.splice(existing, 1)
statusRepeater.items.unshift(newStatus)
statusRepeater.items.length = Math.min(statusRepeater.count, 5)
statusRepeater.itemsChanged()
window.saveState(statusRepeater)
}
setPresence(presence, newStatus)
close()
}
onOpened: statusField.forceActiveFocus()
HLabeledItem { HLabeledItem {
id: statusMsgLabel id: statusMsgLabel
enabled: presence && presence !== "offline" enabled: presence && presence !== "offline"
width: parent.width width: parent.width
height: visible ? implicitHeight : 0 height: visible ? implicitHeight : 0
label.text: qsTr("Status message:") label.text: qsTr("Status message:")
label.horizontalAlignment: Qt.AlignHCenter label.horizontalAlignment: Qt.AlignHCenter
label.leftPadding: theme.spacing
Keys.onDownPressed: onlineButton.forceActiveFocus() label.rightPadding: label.leftPadding
label.topPadding: theme.spacing / 2
label.bottomPadding: label.topPadding
HRowLayout { HRowLayout {
width: parent.width width: parent.width
HTextField { HComboBox {
id: statusText // We use a ComboBox disguised as a field for the
maximumLength: 255 // autosuggestion-as-we-type feature
horizontalAlignment: Qt.AlignHCenter
onAccepted: {
setPresence(presence, statusText.text)
accountMenu.close()
}
defaultText: statusMsg id: statusField
placeholderText: presence ? "" : "Unsupported server" editable: true
indicator: null
popup: null
model: statusRepeater.model
currentIndex: statusRepeater.items.indexOf(
root.currentIndex !== -1 &&
root.itemAt(root.currentIndex).isStatus ?
root.itemAt(root.currentIndex).text :
root.statusMsg
)
field.placeholderText: presence ? "" : "Unsupported server"
field.maximumLength: 255
onAccepted: root.statusFieldApply()
onActiveFocusChanged: if (activeFocus) field.selectAll()
Keys.onBacktabPressed: event => Keys.upPressed(event)
Keys.onTabPressed: event => Keys.downPressed(event)
Keys.onUpPressed: signOutItem.forceActiveFocus()
Keys.onDownPressed:
(statusRepeater.itemAt(0) || onlineItem).forceActiveFocus()
Layout.fillWidth: true Layout.fillWidth: true
} }
@ -56,26 +93,52 @@ HMenu {
icon.name: "apply" icon.name: "apply"
icon.color: theme.colors.positiveBackground icon.color: theme.colors.positiveBackground
onClicked: { onClicked: root.statusFieldApply()
setPresence(presence, statusText.text)
accountMenu.close()
}
Layout.fillHeight: true Layout.fillHeight: true
} }
} }
} }
HMenuSeparator { } HMenuSeparator {}
Repeater {
id: statusRepeater
// Separate property instead of setting model directly so that we can
// manipulate this as a JS list, not a QQmlModel
property var items: window.getState(this, "items", [])
readonly property string saveName: "lastStatus"
readonly property string saveId: "ALL"
readonly property var saveProperties: ["items"]
model: items
delegate: HMenuItem {
readonly property bool isStatus: true
icon.name: "previously-set-status"
text: modelData
onTriggered: root.statusFieldApply(text)
Keys.onBacktabPressed: event => Keys.upPressed(event)
Keys.onUpPressed: event => {
event.accepted = index === 0
if (event.accepted) statusField.forceActiveFocus()
}
}
}
HMenuSeparator { visible: statusRepeater.count > 0 }
HMenuItem { HMenuItem {
id: onlineButton id: onlineItem
icon.name: "presence-online" icon.name: "presence-online"
icon.color: theme.controls.presence.online icon.color: theme.controls.presence.online
text: qsTr("Online") text: qsTr("Online")
onTriggered: setPresence("online") onTriggered: setPresence("online")
Keys.onUpPressed: statusText.forceActiveFocus()
} }
HMenuItem { HMenuItem {
@ -133,11 +196,14 @@ HMenu {
} }
HMenuItemPopupSpawner { HMenuItemPopupSpawner {
id: signOutItem
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")
popup: "Popups/SignOutPopup.qml" popup: "Popups/SignOutPopup.qml"
properties: { "userId": userId } properties: { "userId": userId }
Keys.onDownPressed: statusField.forceActiveFocus()
} }
} }

View File

@ -51,6 +51,9 @@ ApplicationWindow {
} }
function saveState(obj) { function saveState(obj) {
// obj should have these properties: saveName (str),
// saveId (str, default "ALL"), and saveProperties (array of str)
if (! obj.saveName || ! obj.saveProperties || if (! obj.saveName || ! obj.saveProperties ||
obj.saveProperties.length < 1) return obj.saveProperties.length < 1) return

View File

@ -0,0 +1,3 @@
<svg height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg">
<path d="m24 12c0 6.627-5.373 12-12 12s-12-5.373-12-12h2c0 5.514 4.486 10 10 10s10-4.486 10-10-4.486-10-10-10c-2.777 0-5.287 1.141-7.099 2.977l2.061 2.061-6.962 1.354 1.305-7.013 2.179 2.18c2.172-2.196 5.182-3.559 8.516-3.559 6.627 0 12 5.373 12 12zm-13-6v8h7v-2h-5v-6z"/>
</svg>

After

Width:  |  Height:  |  Size: 368 B