linphone-desktop/linphone-app/ui/modules/Common/Picker/EmojiPicker.qml
Julien Wadel c8337d9dda Create thumbnails into memory instead of disk.
Clean unused headers.
2023-04-11 10:22:05 +02:00

273 lines
No EOL
9.1 KiB
QML

import QtQuick 2.7
import QtQuick.Layouts 1.3
import Common 1.0
import Common.Styles 1.0
import Linphone 1.0
import Units 1.0
import UtilsCpp 1.0
import 'qrc:/ui/scripts/Utils/utils.js' as Utils
Item{
id: mainItem
property font customFont : SettingsModel.textMessageFont
signal emojiClicked(var emoji)
width: 500
height: mainLayout.height
property var emojis:{
"emoticons": [[0x1F600, 0x1F64F]]
, "misc": [ [0x1F300, 0x1F5FF],[0x2600, 0x26FF], [0x238C, 0x2426], [0x2440, 0x2449] ]
, "maps": [ [0x1F680, 0x1F6D7], [0x1F6E0, 0x1F6EC], [0x1F6F0, 0x1F6FC] ]
, "flags": [ [0x1F1E6, 0x1F1FF] ]
, "dingbats": [ [0x2700, 0x27B0] ]
, "picto": [ [0x1F900, 0x1F978], [0x1F980, 0x1F9CB], [0x1F9CD, 0x1F9FF] ]
, "asian": [ [0x1F018, 0x1F02B], [0x1F030, 0x1F093], [0x1F0A0, 0x1F0AE], [0x1F0B1, 0x1F0BF], [0x1F0C1, 0x1F0CF], [0x1F0D1, 0x1F0F5], [0x1F100, 0x1F10C], [0x1F110, 0x1F16C], [0x1F170, 0x1F1AC], [0x1F1E6, 0x1F202], [0x1F210, 0x1F23B], [0x1F240, 0x1F248], [0x1F250, 0x1F251], [0x1F260, 0x1F264] ]
, "marks": [ [0x2010, 0x2027], [0x2030, 0x205E], [0x2070, 0x209C], [0x20A0, 0x20BF]] //0x20BF], [0x20D0, 0x20EE] ]
}
function getArrayLength(iconArray){
return iconArray[1] - iconArray[0]
}
property int maxIndex: {
var count = 0
for( var i in emojis){
for(var j in emojis[i]){
count += getArrayLength(emojis[i][j])
}
}
console.log("Max items : " +count)
return count
}
function getEmojiCodeInArray(index, iconArray){
var length = getArrayLength(iconArray)
if( index < length )
return [iconArray[0] + index, index];
else {
return [-1, index - length]
}
}
function getEmojiCodeInMatrix(index, matrix, emojiIndex){
var result = [-1, index]
while(result[0]<0 && emojiIndex < matrix.length) result = getEmojiCodeInArray(result[1], matrix[emojiIndex++])
return result
}
function getEmojiCode(index){
var result = [-1, index]
result = getEmojiCodeInMatrix(result[1], emojis.emoticons, 0)
if(result[0]<0) result = getEmojiCodeInArray(result[1], emojis.misc[0])
else return result[0]
if(result[0]<0) result = getEmojiCodeInArray(result[1], emojis.maps[0])
else return result[0]
if(result[0]<0) result = getEmojiCodeInArray(result[1], emojis.flags[0])
else return result[0]
if(result[0]<0) result = getEmojiCodeInArray(result[1], emojis.dingbats[0])
else return result[0]
if(result[0]<0) result = getEmojiCodeInArray(result[1], emojis.picto[0])
else return result[0]
if(result[0]<0) result = getEmojiCodeInArray(result[1], emojis.asian[0])
else return result[0]
if(result[0]<0) result = getEmojiCodeInArray(result[1], emojis.marks[0])
else return result[0]
if(result[0]<0) result = getEmojiCodeInMatrix(result[1], emojis.misc, 1)
else return result[0]
if(result[0]<0) result = getEmojiCodeInMatrix(result[1], emojis.maps, 1)
else return result[0]
if(result[0]<0) result = getEmojiCodeInMatrix(result[1], emojis.flags, 1)
else return result[0]
if(result[0]<0) result = getEmojiCodeInMatrix(result[1], emojis.dingbats, 1)
else return result[0]
if(result[0]<0) result = getEmojiCodeInMatrix(result[1], emojis.picto, 1)
else return result[0]
if(result[0]<0) result = getEmojiCodeInMatrix(result[1], emojis.asian, 1)
else return result[0]
if(result[0]<0) result = getEmojiCodeInMatrix(result[1], emojis.marks, 1)
else return result[0]
return result[0]
}
MouseArea{
anchors.fill: parent
cursorShape: Qt.ArrowCursor
}
ColumnLayout{
id: mainLayout
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.margins: 5
spacing: 0
Text{
Layout.bottomMargin: 5
Layout.fillWidth: true
//: 'Last used' : Emoji title for last used section.
text: qsTr('emojisLastUsed')
property font customFont : SettingsModel.textMessageFont
font.pointSize: customFont.pointSize
font.family: customFont.family
font.weight: Font.Bold
visible: gridPreferred.model.length > 0
MouseArea{
anchors.fill: parent
onClicked: EmojisSettingsModel.clear()
}
}
GridLayout{
id: gridPreferred
Layout.fillWidth: true
Layout.preferredWidth: parent.width
Layout.preferredHeight: availableRows * emojiSize
property int emojiSize: EmojiPickerStyle.emojiSize + EmojiPickerStyle.emojiMargin // emoji + margin. margin is set here in order to avoid the use of spacing. This way, the height computation is easer to get.
property int availableColumns : width /emojiSize
property int availableRows : (model.length - 1) / availableColumns + 1
columns: availableColumns
columnSpacing: 0
rowSpacing: 0
property var model: EmojisSettingsModel.lastUseds// Use this model inderction becaus eof Repeater that don't refresh values when the model change (that comes from EmojiSettingsModel which is a list of int)
onModelChanged: {
emojisPreferredRepeater.model = 0 // Force reset model
emojisPreferredRepeater.model = model.length
}
Repeater{
id: emojisPreferredRepeater
model: parent.length
Text{
height: gridPreferred.emojiSize
width: gridPreferred.emojiSize
Layout.alignment: Qt.AlignTop | Qt.AlignLeft
font.pointSize: 20
font.family: customFont.family
property int code: gridPreferred.model[index]
property string stringCodePoint: code >=0 ? String.fromCodePoint(code) : ''
text: UtilsCpp.encodeTextToQmlRichFormat(stringCodePoint)
textFormat: Text.RichText
visible: code >= 0
MouseArea{
anchors.fill: parent
onClicked: {console.log("Emoji code : "+code+"(" +parseInt(code, 10).toString(16)+") => "+stringCodePoint);emojiClicked(stringCodePoint)}
}
}
}
Repeater{// Fill empty spaces if needed
model: Math.max(gridPreferred.availableColumns - gridPreferred.model.length, 0)
Item{ height: gridPreferred.emojiSize
width: gridPreferred.emojiSize
}
}
}
Text{
Layout.bottomMargin: 5
Layout.fillWidth: true
//: 'All' Emoji title for all items.
text: qsTr('emojisAll')
property font customFont : SettingsModel.textMessageFont
font.pointSize: customFont.pointSize
font.family: customFont.family
font.weight: Font.Bold
}
GridLayout{
id: grid
Layout.fillWidth: true
Layout.preferredWidth: parent.width
Layout.preferredHeight: availableRows * emojiSize
property int emojiSize: EmojiPickerStyle.emojiSize + EmojiPickerStyle.emojiMargin
property int availableColumns : width /emojiSize
property int availableRows : (grid.auxItemDisplayed + grid.auxItemsCount - 1) / availableColumns + 1
property int auxItemDisplayed:0
property int firstItemDisplayed: 0
property int auxItemsCount: 160
columns: availableColumns
columnSpacing: 0
rowSpacing: 0
Repeater{
id: emojisRepeater
model: grid.auxItemsCount // Repeat prioritized items.
Text{
height: grid.emojiSize
width: grid.emojiSize
Layout.alignment: Qt.AlignTop | Qt.AlignLeft
font.pointSize: 20
font.family: customFont.family
property int code: mainItem.getEmojiCode(index)
property string stringCodePoint: code >=0 ? String.fromCodePoint(code) : ''
text: UtilsCpp.encodeTextToQmlRichFormat(stringCodePoint)
textFormat: Text.RichText
visible: code >=0 && grid.firstItemDisplayed == grid.auxItemsCount
Component.onCompleted: ++grid.firstItemDisplayed
MouseArea{
anchors.fill: parent
onClicked: {console.log("Emoji code : "+code+"(" +parseInt(code, 10).toString(16)+") => "+stringCodePoint);
EmojisSettingsModel.addLastUsed(code);
emojiClicked(stringCodePoint)}
}
}
}
Timer{
id: refreshItems
repeat: true
interval: 1000
running: grid.auxItemDisplayed<mainItem.maxIndex-grid.auxItemsCount
property int lastCount: 0
onTriggered: {
console.log("Loaded emojis : " +(grid.auxItemDisplayed - lastCount))
lastCount = grid.auxItemDisplayed
}
}
// Repeat loader items to load auxillary data without freezing gui or other items.
// Make a Loader of Repeater (to avoid multiple loader) doesn't seems to work (TODO: investigation needed)
Repeater{
model: mainItem.maxIndex - grid.auxItemsCount
Loader{
active: grid.firstItemDisplayed == grid.auxItemsCount
Connections{
target: refreshItems
onTriggered: if(status === Loader.Ready){
++grid.auxItemDisplayed
visible = true
target = null // signal optimization : one-call trigger.
}
}
visible: false
sourceComponent:
Text{
height: grid.emojiSize
width: grid.emojiSize
Layout.alignment: Qt.AlignTop | Qt.AlignLeft
font.pointSize: 20
font.family: customFont.family
property int code: mainItem.getEmojiCode(index+grid.auxItemsCount)
property string stringCodePoint: code >=0 ? String.fromCodePoint(code) : ''
text: UtilsCpp.encodeTextToQmlRichFormat(stringCodePoint)
textFormat: Text.RichText
visible: code >= 0
MouseArea{
anchors.fill: parent
onClicked: {console.log("Emoji code : "+code+"(" +parseInt(code, 10).toString(16)+") => "+stringCodePoint);
EmojisSettingsModel.addLastUsed(code);
emojiClicked(stringCodePoint)}
}
}
}
}
}
}
}