Warning, /network/neochat/src/qml/EmojiPicker.qml is written in an unsupported language. File is not indexed.

0001 // SPDX-FileCopyrightText: 2022 Tobias Fella <tobias.fella@kde.org>
0002 // SPDX-License-Identifier: GPL-2.0-or-later
0003 
0004 import QtQuick
0005 import QtQuick.Controls as QQC2
0006 import QtQuick.Layouts
0007 import org.kde.kirigami as Kirigami
0008 import org.kde.neochat
0009 
0010 ColumnLayout {
0011     id: root
0012 
0013     /**
0014      * @brief The current room that user is viewing.
0015      */
0016     property NeoChatRoom currentRoom
0017 
0018     property bool includeCustom: false
0019     property bool showQuickReaction: false
0020 
0021     readonly property var currentEmojiModel: {
0022         if (includeCustom) {
0023             EmojiModel.categoriesWithCustom;
0024         } else {
0025             EmojiModel.categories;
0026         }
0027     }
0028 
0029     readonly property int categoryIconSize: Math.round(Kirigami.Units.gridUnit * 2.5)
0030     readonly property var currentCategory: currentEmojiModel[categories.currentIndex].category
0031     readonly property alias categoryCount: categories.count
0032     property int selectedType: 0
0033 
0034     signal chosen(string emoji)
0035 
0036     onActiveFocusChanged: if (activeFocus) {
0037         searchField.forceActiveFocus();
0038     }
0039 
0040     spacing: 0
0041 
0042     Kirigami.NavigationTabBar {
0043         id: types
0044         Layout.fillWidth: true
0045         Kirigami.Theme.colorSet: Kirigami.Theme.View
0046 
0047         background: null
0048         actions: [
0049             Kirigami.Action {
0050                 id: emojis
0051                 icon.name: "smiley"
0052                 text: i18n("Emojis")
0053                 checked: true
0054                 onTriggered: root.selectedType = 0
0055             },
0056             Kirigami.Action {
0057                 id: stickers
0058                 icon.name: "stickers"
0059                 text: i18n("Stickers")
0060                 onTriggered: root.selectedType = 1
0061             }
0062         ]
0063     }
0064 
0065     QQC2.ScrollView {
0066         Layout.fillWidth: true
0067         Layout.preferredHeight: root.categoryIconSize + QQC2.ScrollBar.horizontal.height
0068         QQC2.ScrollBar.horizontal.height: QQC2.ScrollBar.horizontal.visible ? QQC2.ScrollBar.horizontal.implicitHeight : 0
0069 
0070         ListView {
0071             id: categories
0072             clip: true
0073             focus: true
0074             orientation: ListView.Horizontal
0075 
0076             Keys.onReturnPressed: if (emojiGrid.count > 0) {
0077                 emojiGrid.focus = true;
0078             }
0079             Keys.onEnterPressed: if (emojiGrid.count > 0) {
0080                 emojiGrid.focus = true;
0081             }
0082 
0083             KeyNavigation.down: emojiGrid.count > 0 ? emojiGrid : categories
0084             KeyNavigation.tab: emojiGrid.count > 0 ? emojiGrid : categories
0085 
0086             keyNavigationEnabled: true
0087             keyNavigationWraps: true
0088             Keys.forwardTo: searchField
0089             interactive: width !== contentWidth
0090 
0091             model: root.selectedType === 0 ? root.currentEmojiModel : stickerPackModel
0092             Component.onCompleted: categories.forceActiveFocus()
0093 
0094             delegate: root.selectedType === 0 ? emojiDelegate : stickerDelegate
0095         }
0096     }
0097 
0098     Kirigami.Separator {
0099         Layout.fillWidth: true
0100         Layout.preferredHeight: 1
0101     }
0102 
0103     Kirigami.SearchField {
0104         id: searchField
0105         Layout.margins: Kirigami.Units.smallSpacing
0106         Layout.fillWidth: true
0107         visible: selectedType === 0
0108 
0109         /**
0110          * The focus is manged by the parent and we don't want to use the standard
0111          * shortcut as it could block other SearchFields from using it.
0112          */
0113         focusSequence: ""
0114     }
0115 
0116     EmojiGrid {
0117         id: emojiGrid
0118         targetIconSize: root.currentCategory === EmojiModel.Custom ? Kirigami.Units.gridUnit * 3 : root.categoryIconSize  // Custom emojis are bigger
0119         model: root.selectedType === 1 ? emoticonFilterModel : searchField.text.length === 0 ? EmojiModel.emojis(root.currentCategory) : (root.includeCustom ? EmojiModel.filterModel(searchField.text, false) : EmojiModel.filterModelNoCustom(searchField.text, false))
0120         Layout.fillWidth: true
0121         Layout.fillHeight: true
0122         withCustom: root.includeCustom
0123         onChosen: unicode => root.chosen(unicode)
0124         header: categories
0125         Keys.forwardTo: searchField
0126         stickers: root.selectedType === 1
0127         onStickerChosen: stickerModel.postSticker(emoticonFilterModel.mapToSource(emoticonFilterModel.index(index, 0)).row)
0128     }
0129 
0130     Kirigami.Separator {
0131         visible: showQuickReaction
0132         Layout.fillWidth: true
0133         Layout.preferredHeight: 1
0134     }
0135 
0136     QQC2.ScrollView {
0137         visible: showQuickReaction
0138         Layout.fillWidth: true
0139         Layout.preferredHeight: root.categoryIconSize + QQC2.ScrollBar.horizontal.height
0140         QQC2.ScrollBar.horizontal.height: QQC2.ScrollBar.horizontal.visible ? QQC2.ScrollBar.horizontal.implicitHeight : 0
0141 
0142         ListView {
0143             id: quickReactions
0144             Layout.fillWidth: true
0145 
0146             model: ["👍", "👎", "😄", "🎉", "😕", "❤", "🚀", "👀"]
0147 
0148             delegate: EmojiDelegate {
0149                 emoji: modelData
0150 
0151                 height: root.categoryIconSize
0152                 width: height
0153 
0154                 onClicked: root.chosen(modelData)
0155             }
0156 
0157             orientation: Qt.Horizontal
0158         }
0159     }
0160 
0161     ImagePacksModel {
0162         id: stickerPackModel
0163         room: root.currentRoom
0164         showStickers: true
0165         showEmoticons: false
0166     }
0167 
0168     StickerModel {
0169         id: stickerModel
0170         model: stickerPackModel
0171         packIndex: 0
0172         room: root.currentRoom
0173     }
0174 
0175     EmoticonFilterModel {
0176         id: emoticonFilterModel
0177         sourceModel: stickerModel
0178         showStickers: true
0179     }
0180 
0181     Component {
0182         id: emojiDelegate
0183         Kirigami.NavigationTabButton {
0184             width: root.categoryIconSize
0185             height: width
0186             checked: categories.currentIndex === model.index
0187             text: modelData ? modelData.emoji : ""
0188             QQC2.ToolTip.text: modelData ? modelData.name : ""
0189             QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
0190             QQC2.ToolTip.visible: hovered
0191             onClicked: {
0192                 categories.currentIndex = index;
0193                 categories.focus = true;
0194             }
0195         }
0196     }
0197 
0198     Component {
0199         id: stickerDelegate
0200         Kirigami.NavigationTabButton {
0201             width: root.categoryIconSize
0202             height: width
0203             checked: stickerModel.packIndex === model.index
0204             contentItem: Image {
0205                 source: model.avatarUrl
0206             }
0207             QQC2.ToolTip.text: model.name
0208             QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
0209             QQC2.ToolTip.visible: hovered && !!model.name
0210             onClicked: stickerModel.packIndex = model.index
0211         }
0212     }
0213 
0214     function clearSearchField() {
0215         searchField.text = "";
0216     }
0217 }