overte-thingvellir/scripts/simplifiedUI/simplifiedEmote/emojiApp/ui/qml/SimplifiedEmoji.qml
2019-08-14 12:03:49 -07:00

278 lines
No EOL
11 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 "qrc:////qml//hifi//simplifiedUI//simplifiedConstants" as SimplifiedConstants
import "../../resources/modules/emojiList.js" as EmojiList
import "./ProgressCircle"
Rectangle {
id: root
color: simplifiedUI.colors.darkBackground
anchors.fill: parent
// Used for the indicator picture
readonly property string emojiBaseURL: "../../resources/images/emojis/png1024/"
// Sprite sheet used for the smaller icons
readonly property string emojiSpriteBaseURL: "../../resources/images/emojis/"
// 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 + ".png";
}
SimplifiedConstants.SimplifiedConstants {
id: simplifiedUI
}
focus: true
ListModel {
id: mainModel
}
Component.onCompleted: {
root.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);
});
// Deleting this might remove any emoji that is shown when you open the app
// Keeping in case the spec design might prefer this instead
root.currentCode = mainModel.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: mainEmojiImage
width: 180
height: 180
anchors.centerIn: parent
source: ""
fillMode: Image.PreserveAspectFit
visible: false
}
Image {
id: mainEmojiLowOpacity
width: 180
height: 180
anchors.centerIn: parent
source: mainEmojiImage.source
opacity: 0.5
fillMode: Image.PreserveAspectFit
visible: true
}
// The overlay used during the pie timeout
ProgressCircle {
property int arcChangeSize: 15
id: progressCircle
anchors.centerIn: mainEmojiImage
size: mainEmojiImage.width * 2
opacity: 0.5
colorCircle: "#FFFFFF"
colorBackground: "#E6E6E6"
showBackground: false
isPie: true
arcBegin: 0
arcEnd: 0
visible: false
}
OpacityMask {
anchors.fill: mainEmojiImage
source: mainEmojiImage
maskSource: progressCircle
}
Timer {
id: arcTimer
interval: 5000
repeat: true
running: false
onTriggered: {
progressCircle.arcEnd = ((progressCircle.arcEnd - progressCircle.arcChangeSize) > 0) ? (progressCircle.arcEnd - progressCircle.arcChangeSize) : 0;
}
}
}
Rectangle {
id: emojiIconListContainer
anchors.top: emojiIndicatorContainer.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
clip: true
color: simplifiedUI.colors.darkBackground
/*
This is what the individual view will be. It's a bit complicated, but it works. Might not be worth
refactoring, but might want to check with Zach if he has an issue with below.
Here is reasoning / logic:
The icons displayed are implemented with a sprite sheet from the previous HTML version.
QML seems to have something that lets you play spritesheet animations, but it doesn't have something
that is like background-position for css.
The way I had to recreate it was to use an Image that has no set size / height and to make sure nothing is transformed
to fit a container.
Then I have to put that in a rectangle that acts like a mask. The x,y position of the image on the emoji meta data is what
is used to move the image x and y itself. The emoji images per sprite shell are 36 x 36. In grid view, there are no spacing
options besides making the cell width and grid have fake extra padding. I can't make that rectangle that is the mask to be larger than 36 by 36.
What worked the best was to make another container rectangle the width of the cell, then positioned the emoji mask rectangle to be centered in that.
The gridview has a function to handle the highlighting which is nice because it comes with an animation already that looks good out the box.
This covers the whole 40X40 cell space.
*/
Component {
id: emojiDelegate
Item {
width: grid.cellWidth; height: grid.cellHeight
Column {
Rectangle {
width: 40
height: 40
color: Qt.rgba(1, 1, 1, 0.0)
Rectangle {
id: imageContainer
anchors.centerIn: parent
clip: true;
z:1
width: 36
height: 36
anchors.leftMargin: 2
anchors.topMargin: 2
x: 1
y: -1
color: Qt.rgba(1, 1, 1, 0.0)
Image {
source: emojiSpriteBaseURL + normal.source
z: 2
fillMode: Image.Pad
x: -normal.frame.x
y: -normal.frame.y
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 = mainModel.get(index).code.utf;
}
onClicked: {
sendToScript({
"source": "SimplifiedEmoji.qml",
"method": "selectedEmoji",
"code": code.utf
});
root.isSelected = true;
root.currentCode = mainModel.get(index).code.utf;
}
onExited: {
}
}
}
}
}
}
}
}
GridView {
id: grid
anchors.fill: parent
anchors.centerIn: parent
anchors.leftMargin: 0
anchors.rightMargin: 0
width: 480
height: 415
cellWidth: 40
cellHeight: 40
model: mainModel
delegate: emojiDelegate
focus: true
highlight: Rectangle { color: Qt.rgba(1, 1, 1, 0.4); radius: 0 }
}
}
signal sendToScript(var message);
function fromScript(message) {
if (message.source !== "simplifiedEmoji.js") {
return;
}
switch(message.method) {
case "beginCountdownTimer":
var degreesInCircle = 360;
progressCircle.arcEnd = degreesInCircle;
arcTimer.interval = message.data.interval;
progressCircle.arcChangeSize = degreesInCircle / (message.data.duration / arcTimer.interval);
arcTimer.start();
root.isSelected = true;
break;
case "clearCountdownTimer":
progressCircle.arcEnd = 0;
arcTimer.stop();
root.isSelected = false;
break;
default:
console.log("Message not recognized from simplifiedEmoji.js", JSON.stringify(message));
}
}
}