overte/scripts/simplifiedUI/simplifiedEmote/emojiApp/ui/qml/SimplifiedEmoji.qml
2019-08-16 12:08:30 -07:00

299 lines
No EOL
9.8 KiB
QML

//
// SimplifiedEmoji.qml
//
// Created by Milad Nazeri on 2019-08-03
// Copyright 2019 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
import QtQuick 2.12
import QtQuick.Controls 2.4
import QtGraphicalEffects 1.12
import stylesUit 1.0 as HifiStylesUit
import TabletScriptingInterface 1.0
import hifi.simplifiedUI.simplifiedControls 1.0 as SimplifiedControls
import hifi.simplifiedUI.simplifiedConstants 1.0 as SimplifiedConstants
import "../../resources/modules/emojiList.js" as EmojiList
import "../../resources/modules/customEmojiList.js" as CustomEmojiList
import "./ProgressCircle"
Rectangle {
id: root
color: simplifiedUI.colors.darkBackground
anchors.fill: parent
// Used for the indicator picture
readonly property string emojiBaseURL: "../../resources/images/emojis/1024px/"
readonly property string emoji52BaseURL: "../../resources/images/emojis/52px/"
// Capture the selected code to handle which emoji to show
property string currentCode: ""
// if this is true, then hovering doesn't allow showing other icons
property bool isSelected: false
// Update the selected emoji image whenever the code property is changed.
onCurrentCodeChanged: {
mainEmojiImage.source = emojiBaseURL + currentCode;
}
SimplifiedConstants.SimplifiedConstants {
id: simplifiedUI
}
focus: true
ListModel {
id: mainModel
}
ListModel {
id: filteredModel
}
Component.onCompleted: {
emojiSearchTextField.forceActiveFocus();
/*
MILAD NOTE:
The emoji list we have is a node transformed list of all the UTF emojis with meta info.
To cut down on the list, this is a good place to start as they will be 90% of the emojis anyone would
want to use.
To save some space, we should probably remove any images from the current ones that aren't the below emojis.
Let's make a separate ticket for this as this is going to need a little work in the current node app. Not much
but I didn't want to focus on it for this sprint.
I can also prune that large emoji json as well to have only the ones we want listed. That can be added to that
ticket as well. This is something I can probably knock out on the plane to Italy becaues I don't want those large
files to be in the repo or loading that big config.json file.
*/
EmojiList.emojiList
.filter(emoji => {
return emoji.mainCategory === "Smileys & Emotion" ||
emoji.mainCategory === "People & Body" ||
emoji.mainCategory === "Animals & Nature" ||
emoji.mainCategory === "Food & Drink";
})
// Convert the filtered list to seed our QML Model used for our view
.forEach(function(item, index){
item.code = { utf: item.code[0] }
item.keywords = { keywords: item.keywords }
mainModel.append(item);
filteredModel.append(item);
});
CustomEmojiList.customEmojiList
.forEach(function(item, index){
item.code = { utf: item.name }
item.keywords = { keywords: item.keywords }
mainModel.append(item);
filteredModel.append(item);
});
root.currentCode = filteredModel.get(0).code.utf;
}
Rectangle {
id: emojiIndicatorContainer
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
height: 200
clip: true
color: simplifiedUI.colors.darkBackground
Image {
id: mainEmojiLowOpacity
width: 180
height: 180
anchors.centerIn: parent
source: mainEmojiImage.source
opacity: 0.5
fillMode: Image.PreserveAspectFit
visible: true
mipmap: true
}
Image {
id: mainEmojiImage
width: 180
height: 180
anchors.centerIn: parent
source: ""
fillMode: Image.PreserveAspectFit
visible: false
mipmap: true
}
// The overlay used during the pie timeout
ProgressCircle {
id: progressCircle
animationDuration: 7000 // Must match `TOTAL_EMOJI_DURATION_MS` in `simplifiedEmoji.js`
anchors.centerIn: mainEmojiImage
size: mainEmojiImage.width * 2
opacity: 0.5
colorCircle: "#FFFFFF"
colorBackground: "#E6E6E6"
showBackground: false
isPie: true
arcBegin: 0
arcEnd: 360
visible: false
}
OpacityMask {
anchors.fill: mainEmojiImage
source: mainEmojiImage
maskSource: progressCircle
}
}
Rectangle {
id: emojiIconListContainer
anchors.top: emojiIndicatorContainer.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: emojiSearchContainer.top
clip: true
color: simplifiedUI.colors.darkBackground
GridView {
id: grid
anchors.fill: parent
anchors.leftMargin: 30
anchors.rightMargin: 24
cellWidth: 60
cellHeight: 60
model: filteredModel
delegate: Image {
width: 52
height: 52
source: emoji52BaseURL + model.code.utf
fillMode: Image.PreserveAspectFit
MouseArea {
hoverEnabled: enabled
anchors.fill: parent
onEntered: {
grid.currentIndex = index
// don't allow a hover image change of the main emoji image
if (root.isSelected) {
return;
}
// Updates the selected image
root.currentCode = model.code.utf;
}
onClicked: {
sendToScript({
"source": "SimplifiedEmoji.qml",
"method": "selectedEmoji",
"code": code.utf
});
root.isSelected = true;
root.currentCode = model.code.utf;
}
}
}
cacheBuffer: 400
focus: true
highlight: Rectangle { color: Qt.rgba(1, 1, 1, 0.4); radius: 0 }
}
SimplifiedControls.VerticalScrollBar {
parent: grid
anchors.rightMargin: -grid.anchors.rightMargin + 2
}
}
Item {
id: emojiSearchContainer
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
height: 40
SimplifiedControls.TextField {
id: emojiSearchTextField
placeholderText: "Search"
maximumLength: 100
clip: true
selectByMouse: true
anchors.left: parent.left
anchors.leftMargin: 16
anchors.right: parent.right
anchors.rightMargin: 16
anchors.verticalCenter: parent.verticalCenter
onTextChanged: {
if (text.length === 0) {
root.filterEmoji(emojiSearchTextField.text);
} else {
waitForMoreInputTimer.restart();
}
}
onAccepted: {
root.filterEmoji(emojiSearchTextField.text);
}
onFocusChanged: {
emojiSearchTextField.autoScroll = focus;
}
}
Timer {
id: waitForMoreInputTimer
repeat: false
running: false
triggeredOnStart: false
interval: 300
onTriggered: {
root.filterEmoji(emojiSearchTextField.text);
}
}
}
function filterEmoji(filterText) {
filteredModel.clear();
if (filterText.length === 0) {
for (var i = 0; i < mainModel.count; i++) {
filteredModel.append(mainModel.get(i));
}
return;
}
for (var i = 0; i < mainModel.count; i++) {
var currentObject = mainModel.get(i);
var currentKeywords = currentObject.keywords.keywords;
for (var j = 0; j < currentKeywords.length; j++) {
if ((currentKeywords[j].toLowerCase()).indexOf(filterText.toLowerCase()) > -1) {
filteredModel.append(mainModel.get(i));
break;
}
}
}
}
signal sendToScript(var message);
function fromScript(message) {
if (message.source !== "simplifiedEmoji.js") {
return;
}
switch(message.method) {
case "beginCountdownTimer":
progressCircle.endAnimation = true;
progressCircle.arcEnd = 0;
root.isSelected = true;
break;
case "clearCountdownTimer":
progressCircle.endAnimation = false;
progressCircle.arcEnd = 360;
progressCircle.endAnimation = true;
root.isSelected = false;
break;
default:
console.log("Message not recognized from simplifiedEmoji.js", JSON.stringify(message));
}
}
}