summary refs log tree commit diff
path: root/resources/qml/emoji/EmojiPicker.qml
diff options
context:
space:
mode:
Diffstat (limited to 'resources/qml/emoji/EmojiPicker.qml')
-rw-r--r--resources/qml/emoji/EmojiPicker.qml290
1 files changed, 290 insertions, 0 deletions
diff --git a/resources/qml/emoji/EmojiPicker.qml b/resources/qml/emoji/EmojiPicker.qml
new file mode 100644

index 00000000..b70923ae --- /dev/null +++ b/resources/qml/emoji/EmojiPicker.qml
@@ -0,0 +1,290 @@ +import QtQuick 2.9 +import QtQuick.Controls 2.9 +import QtQuick.Layouts 1.3 +import QtGraphicalEffects 1.9 + +import im.nheko 1.0 +import im.nheko.EmojiModel 1.0 + +import "../" + +Popup { + + function show(showAt, room_id, event_id) { + console.debug("Showing emojiPicker for " + event_id + "in room " + room_id) + parent = showAt + x = Math.round((showAt.width - width) / 2) + y = showAt.height + emojiPopup.room_id = room_id + emojiPopup.event_id = event_id + open() + } + + property string room_id + property string event_id + property var colors + property alias model: gridView.model + property var textArea + property string emojiCategory: "people" + property real highlightHue: colors.highlight.hslHue + property real highlightSat: colors.highlight.hslSaturation + property real highlightLight: colors.highlight.hslLightness + + id: emojiPopup + + margins: 0 + bottomPadding: 1 + leftPadding: 1 + rightPadding: 1 + + modal: true + focus: true + closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside + + ColumnLayout { + id: columnView + anchors.fill: parent + spacing: 0 + Layout.bottomMargin: 0 + Layout.leftMargin: 3 + Layout.rightMargin: 3 + Layout.topMargin: 2 + + // emoji grid + GridView { + id: gridView + + Layout.preferredHeight: emojiPopup.height + Layout.fillWidth: true + Layout.fillHeight: true + Layout.leftMargin: 4 + + cellWidth: 52 + cellHeight: 52 + + boundsBehavior: Flickable.StopAtBounds + + clip: true + + // Individual emoji + delegate: AbstractButton { + width: 48 + height: 48 + contentItem: Text { + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.family: settings.emojiFont + + font.pixelSize: 36 + text: model.unicode + } + + background: Rectangle { + anchors.fill: parent + color: hovered ? colors.highlight : 'transparent' + radius: 5 + } + + hoverEnabled: true + ToolTip.text: model.shortName + ToolTip.visible: hovered + + // give the emoji a little oomf + DropShadow { + width: parent.width; + height: parent.height; + horizontalOffset: 3 + verticalOffset: 3 + radius: 8.0 + samples: 17 + color: "#80000000" + source: parent.contentItem + } + // TODO: maybe add favorites at some point? + onClicked: { + console.debug("Picked " + model.unicode + "in response to " + emojiPopup.event_id + " in room " + emojiPopup.room_id) + emojiPopup.close() + timelineManager.queueReactionMessage(emojiPopup.room_id, emojiPopup.event_id, model.unicode) + } + } + + // Search field + header: TextField { + id: emojiSearch + anchors.left: parent.left + anchors.right: parent.right + anchors.rightMargin: emojiScroll.width + 4 + placeholderText: qsTr("Search") + selectByMouse: true + rightPadding: clearSearch.width + + Timer { + id: searchTimer + interval: 350 // tweak as needed? + onTriggered: { + emojiPopup.model.filter = emojiSearch.text + emojiPopup.model.category = EmojiCategory.Search + } + } + + ToolButton { + id: clearSearch + anchors { + verticalCenter: parent.verticalCenter + right: parent.right + } + // clear the default hover effects. + background: Item {} + visible: emojiSearch.text !== '' + icon.source: "image://colorimage/:/icons/icons/ui/round-remove-button.png?" + (clearSearch.hovered ? colors.highlight : colors.buttonText) + focusPolicy: Qt.NoFocus + onClicked: emojiSearch.clear() + } + + onTextChanged: searchTimer.restart() + onVisibleChanged: if (visible) forceActiveFocus() + } + + ScrollBar.vertical: ScrollBar { + id: emojiScroll + } + } + + // Separator + Rectangle { + Layout.fillWidth: true + Layout.preferredHeight: 1 + + color: emojiPopup.colors.dark + } + + // Category picker row + RowLayout { + Layout.bottomMargin: 0 + Layout.preferredHeight: 42 + implicitHeight: 42 + Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom + // Display the normal categories + Repeater { + model: ListModel { + // TODO: Would like to get 'simple' icons for the categories + ListElement { image: ":/icons/icons/emoji-categories/people.png"; category: EmojiCategory.People } + ListElement { image: ":/icons/icons/emoji-categories/nature.png"; category: EmojiCategory.Nature } + ListElement { image: ":/icons/icons/emoji-categories/foods.png"; category: EmojiCategory.Food } + ListElement { image: ":/icons/icons/emoji-categories/activity.png"; category: EmojiCategory.Activity } + ListElement { image: ":/icons/icons/emoji-categories/travel.png"; category: EmojiCategory.Travel } + ListElement { image: ":/icons/icons/emoji-categories/objects.png"; category: EmojiCategory.Objects } + ListElement { image: ":/icons/icons/emoji-categories/symbols.png"; category: EmojiCategory.Symbols } + ListElement { image: ":/icons/icons/emoji-categories/flags.png"; category: EmojiCategory.Flags } + } + + delegate: AbstractButton { + Layout.preferredWidth: 36 + Layout.preferredHeight: 36 + + contentItem: Image { + horizontalAlignment: Image.AlignHCenter + verticalAlignment: Image.AlignVCenter + fillMode: Image.Pad + sourceSize.width: 32 + sourceSize.height: 32 + source: "image://colorimage/" + model.image + "?" + (hovered ? colors.highlight : colors.buttonText) + } + + MouseArea + { + id: mouseArea + anchors.fill: parent + onPressed: mouse.accepted = false + cursorShape: Qt.PointingHandCursor + } + + background: Rectangle { + anchors.fill: parent + + color: emojiPopup.model.category === model.category ? Qt.hsla(highlightHue, highlightSat, highlightLight, 0.20) : 'transparent' + radius: 5 + border.color: emojiPopup.model.category === model.category ? colors.highlight : 'transparent' + } + + hoverEnabled: true + ToolTip.text: { + switch (model.category) { + case EmojiCategory.People: + return qsTr('People'); + case EmojiCategory.Nature: + return qsTr('Nature'); + case EmojiCategory.Food: + return qsTr('Food'); + case EmojiCategory.Activity: + return qsTr('Activity'); + case EmojiCategory.Travel: + return qsTr('Travel'); + case EmojiCategory.Objects: + return qsTr('Objects'); + case EmojiCategory.Symbols: + return qsTr('Symbols'); + case EmojiCategory.Flags: + return qsTr('Flags'); + } + } + ToolTip.visible: hovered + + onClicked: { + emojiPopup.model.category = model.category + } + } + } + + // Separator + Rectangle { + Layout.fillHeight: true + Layout.preferredWidth: 1 + implicitWidth: 1 + height: parent.height + + color: emojiPopup.colors.dark + } + + // Search Button is special + AbstractButton { + id: searchBtn + hoverEnabled: true + Layout.alignment: Qt.AlignRight + Layout.bottomMargin: 0 + + ToolTip.text: qsTr("Search") + ToolTip.visible: hovered + onClicked: { + // clear any filters + emojiPopup.model.category = EmojiCategory.Search + gridView.positionViewAtBeginning() + emojiSearch.forceActiveFocus() + } + Layout.preferredWidth: 36 + Layout.preferredHeight: 36 + implicitWidth: 36 + implicitHeight: 36 + + contentItem: Image { + anchors.right: parent.right + horizontalAlignment: Image.AlignHCenter + verticalAlignment: Image.AlignVCenter + sourceSize.width: 32 + sourceSize.height: 32 + fillMode: Image.Pad + smooth: true + source: "image://colorimage/:/icons/icons/ui/search.png?" + (parent.hovered ? colors.highlight : colors.buttonText) + } + + MouseArea + { + id: mouseArea + anchors.fill: parent + onPressed: mouse.accepted = false + cursorShape: Qt.PointingHandCursor + } + } + } + } +}