This is the start of a significant refactoring of everything related to sending messages, which is roughly:
- the chatbox
- action handling
- message sending on the c++ side
- autocompletion of users/rooms/emojis/commands/things i forgot
Notable changes so far include:
- ChatBox is now a ColumnLayout. As part of this, i removed the height animations for now. <del>as far as i can tell, they were broken anyway.</del> I'll readd them later
- Actions were refactored to live outside of the message sending function and are now each an object; it's mostly a wrapper around a function that is executed when the action is invoked
- Everything that used to live in ChatBoxHelper is now in NeoChatRoom; that means that the exact input status (text, message being replied to, message being edited, attachment) is now saved between room switching).
- To edit/reply an event, set `NeoChatRoom::chatBox{edit,reply}Id` to the desired event id, `NeoChatRoom::chatBox{reply,edit}{User,Message}` will then be updated automatically
- Attachments behave equivalently with `NeoChatRoom::chatBoxAttachmentPath`
- Error message reporting from ActionsHandler has been fixed (same fix as in !517) and moved to NeoChatRoom
Broken at the moment:
- [x] Any kind of autocompletion
- [x] Mentions
- [x] Fancy effects
- [x] sed-style edits
- [x] last-user-message edits and replies
- [x] Some of the actions, probably
- [x] Replies from notifications
- [x] Lots of keyboard shortcuts
- [x] Custom emojis
- [x] ChatBox height animations
TODO:
- [x] User / room mentions based on QTextCursors instead of the hack we currently use
- [x] Refactor autocompletion stuff
- [x] ???
- [x] Profit
166 lines
4.8 KiB
QML
166 lines
4.8 KiB
QML
// SPDX-FileCopyrightText: 2018-2019 Black Hat <bhat@encom.eu.org>
|
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
|
|
import QtQuick 2.15
|
|
import QtQuick.Controls 2.15
|
|
import QtQuick.Layouts 1.15
|
|
import org.kde.kirigami 2.15 as Kirigami
|
|
|
|
import org.kde.neochat 1.0
|
|
import NeoChat.Component 1.0
|
|
|
|
ColumnLayout {
|
|
id: _picker
|
|
|
|
property string emojiCategory: "history"
|
|
property var textArea
|
|
readonly property var emojiModel: EmojiModel
|
|
|
|
signal chosen(string emoji)
|
|
|
|
spacing: 0
|
|
|
|
ListView {
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: Kirigami.Units.gridUnit * 2 + 2 // for the focus line
|
|
|
|
boundsBehavior: Flickable.DragOverBounds
|
|
|
|
clip: true
|
|
|
|
orientation: ListView.Horizontal
|
|
|
|
model: ListModel {
|
|
ListElement { label: "custom"; category: "custom" }
|
|
ListElement { label: "⌛️"; category: "history" }
|
|
ListElement { label: "😏"; category: "people" }
|
|
ListElement { label: "🌲"; category: "nature" }
|
|
ListElement { label: "🍛"; category: "food"}
|
|
ListElement { label: "🚁"; category: "activity" }
|
|
ListElement { label: "🚅"; category: "travel" }
|
|
ListElement { label: "💡"; category: "objects" }
|
|
ListElement { label: "🔣"; category: "symbols" }
|
|
ListElement { label: "🏁"; category: "flags" }
|
|
}
|
|
|
|
delegate: ItemDelegate {
|
|
id: del
|
|
|
|
required property string label
|
|
required property string category
|
|
|
|
width: contentItem.Layout.preferredWidth
|
|
height: Kirigami.Units.gridUnit * 2
|
|
|
|
contentItem: Kirigami.Heading {
|
|
horizontalAlignment: Text.AlignHCenter
|
|
verticalAlignment: Text.AlignVCenter
|
|
level: del.label === "custom" ? 4 : 1
|
|
|
|
Layout.preferredWidth: del.label === "custom" ? implicitWidth + Kirigami.Units.largeSpacing : Kirigami.Units.gridUnit * 2
|
|
|
|
font.family: del.label === "custom" ? Kirigami.Theme.defaultFont.family : 'emoji'
|
|
text: del.label === "custom" ? i18n("Custom") : del.label
|
|
}
|
|
|
|
Rectangle {
|
|
anchors.bottom: parent.bottom
|
|
|
|
width: parent.width
|
|
height: 2
|
|
|
|
visible: emojiCategory === category
|
|
|
|
color: Kirigami.Theme.focusColor
|
|
}
|
|
|
|
onClicked: emojiCategory = category
|
|
}
|
|
}
|
|
|
|
Kirigami.Separator {
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: 1
|
|
}
|
|
|
|
GridView {
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: Kirigami.Units.gridUnit * 8
|
|
Layout.fillHeight: true
|
|
|
|
cellWidth: Kirigami.Units.gridUnit * 2
|
|
cellHeight: Kirigami.Units.gridUnit * 2
|
|
|
|
boundsBehavior: Flickable.DragOverBounds
|
|
|
|
clip: true
|
|
|
|
model: {
|
|
switch (emojiCategory) {
|
|
case "custom":
|
|
return CustomEmojiModel
|
|
case "history":
|
|
return emojiModel.history
|
|
case "people":
|
|
return emojiModel.people
|
|
case "nature":
|
|
return emojiModel.nature
|
|
case "food":
|
|
return emojiModel.food
|
|
case "activity":
|
|
return emojiModel.activity
|
|
case "travel":
|
|
return emojiModel.travel
|
|
case "objects":
|
|
return emojiModel.objects
|
|
case "symbols":
|
|
return emojiModel.symbols
|
|
case "flags":
|
|
return emojiModel.flags
|
|
}
|
|
return null
|
|
}
|
|
|
|
delegate: ItemDelegate {
|
|
width: Kirigami.Units.gridUnit * 2
|
|
height: Kirigami.Units.gridUnit * 2
|
|
|
|
contentItem: Kirigami.Heading {
|
|
level: 1
|
|
horizontalAlignment: Text.AlignHCenter
|
|
verticalAlignment: Text.AlignVCenter
|
|
font.family: 'emoji'
|
|
text: modelData.isCustom ? "" : modelData.unicode
|
|
}
|
|
|
|
Image {
|
|
visible: modelData.isCustom
|
|
source: visible ? modelData.unicode : ""
|
|
anchors.fill: parent
|
|
anchors.margins: 2
|
|
|
|
sourceSize.width: width
|
|
sourceSize.height: height
|
|
|
|
Rectangle {
|
|
anchors.fill: parent
|
|
visible: parent.status === Image.Loading
|
|
radius: height/2
|
|
gradient: ShimmerGradient { }
|
|
}
|
|
}
|
|
|
|
onClicked: {
|
|
if (modelData.isCustom) {
|
|
chosen(modelData.shortname)
|
|
} else {
|
|
chosen(modelData.unicode)
|
|
}
|
|
emojiModel.emojiUsed(modelData)
|
|
}
|
|
}
|
|
|
|
ScrollBar.vertical: ScrollBar {}
|
|
}
|
|
}
|