Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nextcloud/desktop.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFelix Weilbach <felix.weilbach@nextcloud.com>2021-09-09 12:18:22 +0300
committerFelix Weilbach <felix.weilbach@nextcloud.com>2021-09-09 12:18:22 +0300
commit8a8d488454405356b5d11f63bebff2d69be43b02 (patch)
treeafa6c5a496561e6778227ece22a6c871622af926
parentf34d66302942ede371bf7bc5d5e213b6c41ea5d8 (diff)
Add dialog to set user status
Signed-off-by: Felix Weilbach <felix.weilbach@nextcloud.com>
-rw-r--r--resources.qrc4
-rw-r--r--src/gui/CMakeLists.txt5
-rw-r--r--src/gui/EmojiPicker.qml112
-rw-r--r--src/gui/ErrorBox.qml26
-rw-r--r--src/gui/UserStatusSelector.qml199
-rw-r--r--src/gui/UserStatusSelectorDialog.qml29
-rw-r--r--src/gui/accountstate.cpp27
-rw-r--r--src/gui/accountstate.h24
-rw-r--r--src/gui/emojimodel.cpp1571
-rw-r--r--src/gui/emojimodel.h137
-rw-r--r--src/gui/main.cpp12
-rw-r--r--src/gui/socketapi/socketapi.cpp2
-rw-r--r--src/gui/tray/UserLine.qml28
-rw-r--r--src/gui/tray/UserModel.cpp34
-rw-r--r--src/gui/tray/UserModel.h6
-rw-r--r--src/gui/tray/Window.qml13
-rw-r--r--src/gui/userstatus.cpp126
-rw-r--r--src/gui/userstatus.h61
-rw-r--r--src/gui/userstatusselectormodel.cpp474
-rw-r--r--src/gui/userstatusselectormodel.h145
-rw-r--r--src/libsync/CMakeLists.txt3
-rw-r--r--src/libsync/abstractnetworkjob.cpp9
-rw-r--r--src/libsync/abstractnetworkjob.h3
-rw-r--r--src/libsync/account.cpp37
-rw-r--r--src/libsync/account.h11
-rw-r--r--src/libsync/capabilities.cpp20
-rw-r--r--src/libsync/capabilities.h2
-rw-r--r--src/libsync/clientsideencryption.cpp13
-rw-r--r--src/libsync/clientsideencryption.h2
-rw-r--r--src/libsync/clientsideencryptionjobs.cpp17
-rw-r--r--src/libsync/datetimeprovider.cpp17
-rw-r--r--src/libsync/datetimeprovider.h18
-rw-r--r--src/libsync/networkjobs.cpp38
-rw-r--r--src/libsync/networkjobs.h25
-rw-r--r--src/libsync/ocsuserstatusconnector.cpp455
-rw-r--r--src/libsync/ocsuserstatusconnector.h70
-rw-r--r--src/libsync/userstatusconnector.cpp121
-rw-r--r--src/libsync/userstatusconnector.h138
-rw-r--r--test/CMakeLists.txt1
-rw-r--r--test/testcapabilities.cpp76
-rw-r--r--test/testpushnotifications.cpp28
-rw-r--r--test/testsetuserstatusdialog.cpp747
42 files changed, 4592 insertions, 294 deletions
diff --git a/resources.qrc b/resources.qrc
index 9fa393c4e..f811db0f7 100644
--- a/resources.qrc
+++ b/resources.qrc
@@ -1,5 +1,9 @@
<RCC>
<qresource prefix="/qml">
+ <file>src/gui/UserStatusSelector.qml</file>
+ <file>src/gui/UserStatusSelectorDialog.qml</file>
+ <file>src/gui/EmojiPicker.qml</file>
+ <file>src/gui/ErrorBox.qml</file>
<file>src/gui/tray/Window.qml</file>
<file>src/gui/tray/UserLine.qml</file>
<file>src/gui/tray/HeaderButton.qml</file>
diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt
index 67a2c7323..74c460d06 100644
--- a/src/gui/CMakeLists.txt
+++ b/src/gui/CMakeLists.txt
@@ -35,6 +35,8 @@ set(client_UI_SRCS
addcertificatedialog.ui
proxyauthdialog.ui
mnemonicdialog.ui
+ UserStatusSelector.qml
+ UserStatusSelectorDialog.qml
tray/ActivityActionButton.qml
tray/ActivityItem.qml
tray/Window.qml
@@ -92,7 +94,6 @@ set(client_SRCS
systray.cpp
thumbnailjob.cpp
userinfo.cpp
- userstatus.cpp
accountstate.cpp
addcertificatedialog.cpp
authenticationdialog.cpp
@@ -106,6 +107,8 @@ set(client_SRCS
iconjob.cpp
iconutils.cpp
remotewipe.cpp
+ userstatusselectormodel.cpp
+ emojimodel.cpp
tray/ActivityData.cpp
tray/ActivityListModel.cpp
tray/UserModel.cpp
diff --git a/src/gui/EmojiPicker.qml b/src/gui/EmojiPicker.qml
new file mode 100644
index 000000000..6a66dbdcb
--- /dev/null
+++ b/src/gui/EmojiPicker.qml
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) by Felix Weilbach <felix.weilbach@nextcloud.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+import QtQuick 2.15
+import QtQuick.Controls 2.15
+import QtQuick.Layouts 1.15
+
+import com.nextcloud.desktopclient 1.0 as NC
+
+ColumnLayout {
+ NC.EmojiModel {
+ id: emojiModel
+ }
+
+ signal chosen(string emoji)
+
+ spacing: 0
+
+ FontMetrics {
+ id: metrics
+ }
+
+ ListView {
+ id: headerLayout
+ Layout.fillWidth: true
+ implicitWidth: contentItem.childrenRect.width
+ implicitHeight: metrics.height * 2
+
+ orientation: ListView.Horizontal
+
+ model: emojiModel.emojiCategoriesModel
+
+ delegate: ItemDelegate {
+ width: metrics.height * 2
+ height: headerLayout.height
+
+ contentItem: Text {
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ text: emoji
+ }
+
+ Rectangle {
+ anchors.bottom: parent.bottom
+
+ width: parent.width
+ height: 2
+
+ visible: ListView.isCurrentItem
+
+ color: "grey"
+ }
+
+
+ onClicked: {
+ emojiModel.setCategory(label)
+ }
+ }
+
+ }
+
+ Rectangle {
+ height: 1
+ Layout.fillWidth: true
+ color: "grey"
+ }
+
+ GridView {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ Layout.preferredHeight: metrics.height * 8
+
+ cellWidth: metrics.height * 2
+ cellHeight: metrics.height * 2
+
+ boundsBehavior: Flickable.DragOverBounds
+ clip: true
+
+ model: emojiModel.model
+
+ delegate: ItemDelegate {
+
+ width: metrics.height * 2
+ height: metrics.height * 2
+
+ contentItem: Text {
+ anchors.centerIn: parent
+ text: modelData === undefined ? "" : modelData.unicode
+ }
+
+ onClicked: {
+ chosen(modelData.unicode);
+ emojiModel.emojiUsed(modelData);
+ }
+ }
+
+ ScrollBar.vertical: ScrollBar {}
+
+ }
+
+}
diff --git a/src/gui/ErrorBox.qml b/src/gui/ErrorBox.qml
new file mode 100644
index 000000000..5b0d102ad
--- /dev/null
+++ b/src/gui/ErrorBox.qml
@@ -0,0 +1,26 @@
+import QtQuick 2.15
+
+Item {
+ id: errorBox
+
+ property var text: ""
+
+ implicitHeight: errorMessage.implicitHeight + 2 * 8
+
+ Rectangle {
+ anchors.fill: parent
+ color: "red"
+ border.color: "black"
+ }
+
+ Text {
+ id: errorMessage
+
+ anchors.fill: parent
+ anchors.margins: 8
+ width: parent.width
+ color: "white"
+ wrapMode: Text.WordWrap
+ text: errorBox.text
+ }
+}
diff --git a/src/gui/UserStatusSelector.qml b/src/gui/UserStatusSelector.qml
new file mode 100644
index 000000000..c879df442
--- /dev/null
+++ b/src/gui/UserStatusSelector.qml
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) by Felix Weilbach <felix.weilbach@nextcloud.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+import QtQuick 2.6
+import QtQuick.Dialogs 1.3
+import QtQuick.Layouts 1.15
+import QtQuick.Controls 2.15
+import QtQuick.Window 2.15
+import com.nextcloud.desktopclient 1.0 as NC
+
+ColumnLayout {
+ id: rootLayout
+ spacing: 0
+ property NC.UserStatusSelectorModel userStatusSelectorModel
+
+ FontMetrics {
+ id: metrics
+ }
+
+ Text {
+ Layout.topMargin: 16
+ Layout.leftMargin: 8
+ Layout.rightMargin: 8
+ Layout.bottomMargin: 8
+ Layout.alignment: Qt.AlignTop | Qt.AlignHCenter
+ font.bold: true
+ text: qsTr("Online status")
+ }
+
+ GridLayout {
+ Layout.margins: 8
+ Layout.alignment: Qt.AlignTop
+ columns: 2
+ rows: 2
+ columnSpacing: 8
+ rowSpacing: 8
+
+ Button {
+ Layout.fillWidth: true
+ checked: NC.UserStatus.Online == userStatusSelectorModel.onlineStatus
+ checkable: true
+ icon.source: userStatusSelectorModel.onlineIcon
+ icon.color: "transparent"
+ text: qsTr("Online")
+ onClicked: userStatusSelectorModel.setOnlineStatus(NC.UserStatus.Online)
+ implicitWidth: 100
+ }
+ Button {
+ Layout.fillWidth: true
+ checked: NC.UserStatus.Away == userStatusSelectorModel.onlineStatus
+ checkable: true
+ icon.source: userStatusSelectorModel.awayIcon
+ icon.color: "transparent"
+ text: qsTr("Away")
+ onClicked: userStatusSelectorModel.setOnlineStatus(NC.UserStatus.Away)
+ implicitWidth: 100
+
+ }
+ Button {
+ Layout.fillWidth: true
+ checked: NC.UserStatus.DoNotDisturb == userStatusSelectorModel.onlineStatus
+ checkable: true
+ icon.source: userStatusSelectorModel.dndIcon
+ icon.color: "transparent"
+ text: qsTr("Do not disturb")
+ onClicked: userStatusSelectorModel.setOnlineStatus(NC.UserStatus.DoNotDisturb)
+ implicitWidth: 100
+ }
+ Button {
+ Layout.fillWidth: true
+ checked: NC.UserStatus.Invisible == userStatusSelectorModel.onlineStatus
+ checkable: true
+ icon.source: userStatusSelectorModel.invisibleIcon
+ icon.color: "transparent"
+ text: qsTr("Invisible")
+ onClicked: userStatusSelectorModel.setOnlineStatus(NC.UserStatus.Invisible)
+ implicitWidth: 100
+ }
+ }
+
+ Text {
+ Layout.topMargin: 16
+ Layout.leftMargin: 8
+ Layout.rightMargin: 8
+ Layout.bottomMargin: 8
+ Layout.alignment: Qt.AlignTop | Qt.AlignHCenter
+ font.bold: true
+ text: qsTr("Status message")
+ }
+
+ RowLayout {
+ Layout.topMargin: 8
+ Layout.leftMargin: 8
+ Layout.rightMargin: 8
+ Layout.bottomMargin: 16
+ Layout.alignment: Qt.AlignTop
+ Layout.fillWidth: true
+
+ Button {
+ Layout.preferredWidth: userStatusMessageTextField.height // metrics.height * 2
+ Layout.preferredHeight: userStatusMessageTextField.height // metrics.height * 2
+ text: userStatusSelectorModel.userStatusEmoji
+ onClicked: emojiDialog.open()
+ }
+
+ Popup {
+ id: emojiDialog
+ padding: 0
+ margins: 0
+
+ anchors.centerIn: Overlay.overlay
+
+ EmojiPicker {
+ id: emojiPicker
+
+ onChosen: {
+ userStatusSelectorModel.userStatusEmoji = emoji
+ emojiDialog.close()
+ }
+ }
+ }
+
+ TextField {
+ id: userStatusMessageTextField
+ Layout.fillWidth: true
+ placeholderText: qsTr("What is your Status?")
+ text: userStatusSelectorModel.userStatusMessage
+ onEditingFinished: userStatusSelectorModel.setUserStatusMessage(text)
+ }
+ }
+
+ Repeater {
+ model: userStatusSelectorModel.predefinedStatusesCount
+
+ Button {
+ id: control
+ Layout.fillWidth: true
+ flat: !hovered
+ hoverEnabled: true
+ text: userStatusSelectorModel.predefinedStatus(index).icon + " <b>" + userStatusSelectorModel.predefinedStatus(index).message + "</b> - " + userStatusSelectorModel.predefinedStatusClearAt(index)
+ onClicked: userStatusSelectorModel.setPredefinedStatus(index)
+ }
+ }
+
+ RowLayout {
+ Layout.topMargin: 16
+ Layout.leftMargin: 8
+ Layout.rightMargin: 8
+ Layout.bottomMargin: 8
+ Layout.alignment: Qt.AlignTop
+
+ Text {
+ text: qsTr("Clear status message after")
+ }
+
+ ComboBox {
+ Layout.fillWidth: true
+ model: userStatusSelectorModel.clearAtValues
+ displayText: userStatusSelectorModel.clearAt
+ onActivated: userStatusSelectorModel.setClearAt(index)
+ }
+ }
+
+ RowLayout {
+ Layout.margins: 8
+ Layout.alignment: Qt.AlignTop
+
+ Button {
+ Layout.fillWidth: true
+ text: qsTr("Clear status message")
+ onClicked: userStatusSelectorModel.clearUserStatus()
+ }
+ Button {
+ highlighted: true
+ Layout.fillWidth: true
+ text: qsTr("Set status message")
+ onClicked: userStatusSelectorModel.setUserStatus()
+ }
+ }
+
+ ErrorBox {
+ Layout.margins: 8
+ Layout.fillWidth: true
+
+ visible: userStatusSelectorModel.errorMessage != ""
+ text: "<b>Error:</b> " + userStatusSelectorModel.errorMessage
+ }
+}
diff --git a/src/gui/UserStatusSelectorDialog.qml b/src/gui/UserStatusSelectorDialog.qml
new file mode 100644
index 000000000..624b24f86
--- /dev/null
+++ b/src/gui/UserStatusSelectorDialog.qml
@@ -0,0 +1,29 @@
+import QtQuick.Window 2.15
+
+import com.nextcloud.desktopclient 1.0 as NC
+
+Window {
+ id: dialog
+
+ property NC.UserStatusSelectorModel model: NC.UserStatusSelectorModel {
+ onFinished: {
+ dialog.close()
+ }
+ }
+
+ width: view.implicitWidth
+ height: view.implicitHeight
+ minimumWidth: view.implicitWidth
+ minimumHeight: view.implicitHeight
+ maximumWidth: view.implicitWidth
+ maximumHeight: view.implicitHeight
+
+ visible: true
+
+ flags: Qt.Dialog
+
+ UserStatusSelector {
+ id: view
+ userStatusSelectorModel: model
+ }
+}
diff --git a/src/gui/accountstate.cpp b/src/gui/accountstate.cpp
index bb2ab5273..7521dac79 100644
--- a/src/gui/accountstate.cpp
+++ b/src/gui/accountstate.cpp
@@ -44,7 +44,6 @@ AccountState::AccountState(AccountPtr account)
, _waitingForNewCredentials(false)
, _maintenanceToConnectedDelay(60000 + (qrand() % (4 * 60000))) // 1-5min delay
, _remoteWipe(new RemoteWipe(_account))
- , _userStatus(new UserStatus(this))
, _isDesktopNotificationsAllowed(true)
{
qRegisterMetaType<AccountState *>("AccountState*");
@@ -127,26 +126,6 @@ void AccountState::setState(State state)
emit stateChanged(_state);
}
-UserStatus::Status AccountState::status() const
-{
- return _userStatus->status();
-}
-
-QString AccountState::statusMessage() const
-{
- return _userStatus->message();
-}
-
-QUrl AccountState::statusIcon() const
-{
- return _userStatus->icon();
-}
-
-QString AccountState::statusEmoji() const
-{
- return _userStatus->emoji();
-}
-
QString AccountState::stateString(State state)
{
switch (state) {
@@ -462,12 +441,6 @@ void AccountState::fetchNavigationApps(){
job->getNavigationApps();
}
-void AccountState::fetchUserStatus()
-{
- connect(_userStatus, &UserStatus::fetchUserStatusFinished, this, &AccountState::statusChanged);
- _userStatus->fetchUserStatus(_account);
-}
-
void AccountState::slotEtagResponseHeaderReceived(const QByteArray &value, int statusCode){
if(statusCode == 200){
qCDebug(lcAccountState) << "New navigation apps ETag Response Header received " << value;
diff --git a/src/gui/accountstate.h b/src/gui/accountstate.h
index 74e41ad6a..7946e2f96 100644
--- a/src/gui/accountstate.h
+++ b/src/gui/accountstate.h
@@ -21,7 +21,7 @@
#include <QPointer>
#include "connectionvalidator.h"
#include "creds/abstractcredentials.h"
-#include "userstatus.h"
+
#include <memory>
class QSettings;
@@ -162,23 +162,6 @@ public:
///Asks for user credentials
void handleInvalidCredentials();
- /** Returns the user status (Online, Dnd, Away, Offline, Invisible)
- * https://gist.github.com/georgehrke/55a0412007f13be1551d1f9436a39675
- */
- UserStatus::Status status() const;
-
- /** Returns the user status Message (text)
- */
- QString statusMessage() const;
-
- /** Returns the user status icon url
- */
- QUrl statusIcon() const;
-
- /** Returns the user status emoji
- */
- QString statusEmoji() const;
-
/** Returns the notifications status retrieved by the notificatons endpoint
* https://github.com/nextcloud/desktop/issues/2318#issuecomment-680698429
*/
@@ -188,10 +171,6 @@ public:
*/
void setDesktopNotificationsAllowed(bool isAllowed);
- /** Fetch the user status (status, icon, message)
- */
- void fetchUserStatus();
-
public slots:
/// Triggers a ping to the server to update state and
/// connection status and errors.
@@ -256,7 +235,6 @@ private:
*/
AccountAppList _apps;
- UserStatus *_userStatus;
bool _isDesktopNotificationsAllowed;
};
diff --git a/src/gui/emojimodel.cpp b/src/gui/emojimodel.cpp
new file mode 100644
index 000000000..e6b281db1
--- /dev/null
+++ b/src/gui/emojimodel.cpp
@@ -0,0 +1,1571 @@
+/*
+ * Copyright (C) by Felix Weilbach <felix.weilbach@nextcloud.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <QtGlobal>
+#include <memory>
+
+#include "emojimodel.h"
+
+namespace OCC {
+
+QVariant EmojiCategoriesModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid()) {
+ return {};
+ }
+
+ switch (role) {
+ case Roles::EmojiRole:
+ return categories[index.row()].emoji;
+
+ case Roles::LabelRole:
+ return categories[index.row()].label;
+ }
+
+ return {};
+}
+
+int EmojiCategoriesModel::rowCount(const QModelIndex &parent) const
+{
+ Q_UNUSED(parent);
+ return static_cast<int>(categories.size());
+}
+
+QHash<int, QByteArray> EmojiCategoriesModel::roleNames() const
+{
+ QHash<int, QByteArray> roles;
+ roles[Roles::EmojiRole] = "emoji";
+ roles[Roles::LabelRole] = "label";
+ return roles;
+}
+
+const std::vector<EmojiCategoriesModel::Category> EmojiCategoriesModel::categories = {
+ { "⌛️", "history" },
+ { "😏", "people" },
+ { "🌲", "nature" },
+ { "🍛", "food" },
+ { "🚁", "activity" },
+ { "🚅", "travel" },
+ { "💡", "objects" },
+ { "🔣", "symbols" },
+ { "🏁", "flags" },
+};
+
+QVariantList EmojiModel::history() const
+{
+ return _settings.value("Editor/emojis", QVariantList()).toList();
+}
+
+void EmojiModel::setCategory(const QString &category)
+{
+ if (_category == category) {
+ return;
+ }
+ _category = category;
+ emit modelChanged();
+}
+
+QAbstractListModel *EmojiModel::emojiCategoriesModel()
+{
+ return &_emojiCategoriesModel;
+}
+
+QVariantList EmojiModel::model() const
+{
+ if (_category == "history") {
+ return history();
+ } else if (_category == "people") {
+ return people;
+ } else if (_category == "nature") {
+ return nature;
+ } else if (_category == "food") {
+ return food;
+ } else if (_category == "activity") {
+ return activity;
+ } else if (_category == "travel") {
+ return travel;
+ } else if (_category == "objects") {
+ return objects;
+ } else if (_category == "symbols") {
+ return symbols;
+ } else if (_category == "flags") {
+ return flags;
+ }
+ return history();
+}
+
+void EmojiModel::emojiUsed(const QVariant &modelData)
+{
+ auto historyEmojis = history();
+
+ auto historyEmojisIter = historyEmojis.begin();
+ while (historyEmojisIter != historyEmojis.end()) {
+ if ((*historyEmojisIter).value<Emoji>().unicode == modelData.value<Emoji>().unicode) {
+ historyEmojisIter = historyEmojis.erase(historyEmojisIter);
+ } else {
+ historyEmojisIter++;
+ }
+ }
+
+ historyEmojis.push_front(modelData);
+ _settings.setValue("Editor/emojis", historyEmojis);
+
+ emit historyChanged();
+}
+
+const QVariantList EmojiModel::people = {
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x98\x80"), ":grinning:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x98\x81"), ":grin:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x98\x82"), ":joy:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa4\xa3"), ":rofl:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x98\x83"), ":smiley:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x98\x84"), ":smile:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x98\x85"), ":sweat_smile:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x98\x86"), ":laughing:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x98\x89"), ":wink:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x98\x8a"), ":blush:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x98\x8b"), ":yum:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x98\x8e"), ":sunglasses:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x98\x8d"), ":heart_eyes:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x98\x98"), ":kissing_heart:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x98\x97"), ":kissing:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x98\x99"), ":kissing_smiling_eyes:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x98\x9a"), ":kissing_closed_eyes:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x98\xba"), ":relaxed:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x99\x82"), ":slight_smile:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa4\x97"), ":hugging:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa4\x94"), ":thinking:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x98\x90"), ":neutral_face:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x98\x91"), ":expressionless:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x98\xb6"), ":no_mouth:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x99\x84"), ":rolling_eyes:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x98\x8f"), ":smirk:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x98\xa3"), ":persevere:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x98\xa5"), ":disappointed_relieved:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x98\xae"), ":open_mouth:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa4\x90"), ":zipper_mouth:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x98\xaf"), ":hushed:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x98\xaa"), ":sleepy:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x98\xab"), ":tired_face:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x98\xb4"), ":sleeping:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x98\x8c"), ":relieved:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa4\x93"), ":nerd:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x98\x9b"), ":stuck_out_tongue:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x98\x9c"), ":stuck_out_tongue_winking_eye:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x98\x9d"), ":stuck_out_tongue_closed_eyes:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa4\xa4"), ":drooling_face:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x98\x92"), ":unamused:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x98\x93"), ":sweat:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x98\x94"), ":pensive:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x98\x95"), ":confused:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x99\x83"), ":upside_down:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa4\x91"), ":money_mouth:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x98\xb2"), ":astonished:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x98\xb9"), ":frowning2:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x99\x81"), ":slight_frown:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x98\x96"), ":confounded:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x98\x9e"), ":disappointed:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x98\x9f"), ":worried:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x98\xa4"), ":triumph:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x98\xa2"), ":cry:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x98\xad"), ":sob:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x98\xa6"), ":frowning:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x98\xa7"), ":anguished:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x98\xa8"), ":fearful:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x98\xa9"), ":weary:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x98\xac"), ":grimacing:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x98\xb0"), ":cold_sweat:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x98\xb1"), ":scream:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x98\xb3"), ":flushed:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x98\xb5"), ":dizzy_face:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x98\xa1"), ":rage:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x98\xa0"), ":angry:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x98\x87"), ":innocent:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa4\xa0"), ":cowboy:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa4\xa1"), ":clown:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa4\xa5"), ":lying_face:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x98\xb7"), ":mask:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa4\x92"), ":thermometer_face:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa4\x95"), ":head_bandage:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa4\xa2"), ":nauseated_face:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa4\xa7"), ":sneezing_face:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x98\x88"), ":smiling_imp:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x91\xbf"), ":imp:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x91\xb9"), ":japanese_ogre:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x91\xba"), ":japanese_goblin:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x92\x80"), ":skull:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x91\xbb"), ":ghost:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x91\xbd"), ":alien:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa4\x96"), ":robot:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x92\xa9"), ":poop:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x98\xba"), ":smiley_cat:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x98\xb8"), ":smile_cat:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x98\xb9"), ":joy_cat:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x98\xbb"), ":heart_eyes_cat:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x98\xbc"), ":smirk_cat:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x98\xbd"), ":kissing_cat:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x99\x80"), ":scream_cat:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x98\xbf"), ":crying_cat_face:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x98\xbe"), ":pouting_cat:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x91\xa6"), ":boy:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x91\xa7"), ":girl:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x91\xa8"), ":man:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x91\xa9"), ":woman:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x91\xb4"), ":older_man:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x91\xb5"), ":older_woman:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x91\xb6"), ":baby:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x91\xbc"), ":angel:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x91\xae"), ":cop:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x95\xb5"), ":spy:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x92\x82"), ":guardsman:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x91\xb7"), ":construction_worker:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x91\xb3"), ":man_with_turban:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x91\xb1"), ":person_with_blond_hair:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8e\x85"), ":santa:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa4\xb6"), ":mrs_claus:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x91\xb8"), ":princess:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa4\xb4"), ":prince:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x91\xb0"), ":bride_with_veil:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa4\xb5"), ":man_in_tuxedo:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa4\xb0"), ":pregnant_woman:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x91\xb2"), ":man_with_gua_pi_mao:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x99\x8d"), ":person_frowning:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x99\x8e"), ":person_with_pouting_face:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x99\x85"), ":no_good:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x99\x86"), ":ok_woman:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x92\x81"), ":information_desk_person:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x99\x8b"), ":raising_hand:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x99\x87"), ":bow:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa4\xa6"), ":face_palm:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa4\xb7"), ":shrug:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x92\x86"), ":massage:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x92\x87"), ":haircut:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\xb6"), ":walking:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\x83"), ":runner:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x92\x83"), ":dancer:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x95\xba"), ":man_dancing:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x91\xaf"), ":dancers:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x97\xa3"), ":speaking_head:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x91\xa4"), ":bust_in_silhouette:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x91\xa5"), ":busts_in_silhouette:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x91\xab"), ":couple:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x91\xac"), ":two_men_holding_hands:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x91\xad"), ":two_women_holding_hands:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x92\x8f"), ":couplekiss:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x92\x91"), ":couple_with_heart:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x91\xaa"), ":family:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x92\xaa"), ":muscle:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa4\xb3"), ":selfie:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x91\x88"), ":point_left:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x91\x89"), ":point_right:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x98\x9d"), ":point_up:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x91\x86"), ":point_up_2:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x96\x95"), ":middle_finger:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x91\x87"), ":point_down:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9c\x8c"), ":v:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa4\x9e"), ":fingers_crossed:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x96\x96"), ":vulcan:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa4\x98"), ":metal:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa4\x99"), ":call_me:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x96\x90"), ":hand_splayed:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9c\x8b"), ":raised_hand:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x91\x8c"), ":ok_hand:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x91\x8d"), ":thumbsup:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x91\x8e"), ":thumbsdown:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9c\x8a"), ":fist:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x91\x8a"), ":punch:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa4\x9b"), ":left_facing_fist:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa4\x9c"), ":right_facing_fist:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa4\x9a"), ":raised_back_of_hand:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x91\x8b"), ":wave:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x91\x8f"), ":clap:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9c\x8d"), ":writing_hand:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x91\x90"), ":open_hands:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x99\x8c"), ":raised_hands:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x99\x8f"), ":pray:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa4\x9d"), ":handshake:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x92\x85"), ":nail_care:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x91\x82"), ":ear:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x91\x83"), ":nose:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x91\xa3"), ":footprints:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x91\x80"), ":eyes:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x91\x81"), ":eye:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x91\x85"), ":tongue:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x91\x84"), ":lips:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x92\x8b"), ":kiss:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x92\xa4"), ":zzz:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x91\x93"), ":eyeglasses:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x95\xb6"), ":dark_sunglasses:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x91\x94"), ":necktie:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x91\x95"), ":shirt:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x91\x96"), ":jeans:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x91\x97"), ":dress:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x91\x98"), ":kimono:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x91\x99"), ":bikini:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x91\x9a"), ":womans_clothes:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x91\x9b"), ":purse:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x91\x9c"), ":handbag:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x91\x9d"), ":pouch:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8e\x92"), ":school_satchel:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x91\x9e"), ":mans_shoe:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x91\x9f"), ":athletic_shoe:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x91\xa0"), ":high_heel:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x91\xa1"), ":sandal:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x91\xa2"), ":boot:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x91\x91"), ":crown:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x91\x92"), ":womans_hat:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8e\xa9"), ":tophat:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8e\x93"), ":mortar_board:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9b\x91"), ":helmet_with_cross:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x92\x84"), ":lipstick:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x92\x8d"), ":ring:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8c\x82"), ":closed_umbrella:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x92\xbc"), ":briefcase:" }),
+};
+
+const QVariantList EmojiModel::nature = {
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x99\x88"), ":see_no_evil:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x99\x89"), ":hear_no_evil:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x99\x8a"), ":speak_no_evil:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x92\xa6"), ":sweat_drops:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x92\xa8"), ":dash:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x90\xb5"), ":monkey_face:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x90\x92"), ":monkey:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa6\x8d"), ":gorilla:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x90\xb6"), ":dog:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x90\x95"), ":dog2:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x90\xa9"), ":poodle:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x90\xba"), ":wolf:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa6\x8a"), ":fox:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x90\xb1"), ":cat:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x90\x88"), ":cat2:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa6\x81"), ":lion_face:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x90\xaf"), ":tiger:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x90\x85"), ":tiger2:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x90\x86"), ":leopard:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x90\xb4"), ":horse:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x90\x8e"), ":racehorse:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa6\x8c"), ":deer:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa6\x84"), ":unicorn:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x90\xae"), ":cow:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x90\x82"), ":ox:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x90\x83"), ":water_buffalo:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x90\x84"), ":cow2:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x90\xb7"), ":pig:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x90\x96"), ":pig2:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x90\x97"), ":boar:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x90\xbd"), ":pig_nose:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x90\x8f"), ":ram:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x90\x91"), ":sheep:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x90\x90"), ":goat:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x90\xaa"), ":dromedary_camel:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x90\xab"), ":camel:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x90\x98"), ":elephant:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa6\x8f"), ":rhino:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x90\xad"), ":mouse:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x90\x81"), ":mouse2:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x90\x80"), ":rat:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x90\xb9"), ":hamster:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x90\xb0"), ":rabbit:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x90\x87"), ":rabbit2:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x90\xbf"), ":chipmunk:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa6\x87"), ":bat:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x90\xbb"), ":bear:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x90\xa8"), ":koala:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x90\xbc"), ":panda_face:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x90\xbe"), ":feet:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa6\x83"), ":turkey:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x90\x94"), ":chicken:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x90\x93"), ":rooster:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x90\xa3"), ":hatching_chick:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x90\xa4"), ":baby_chick:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x90\xa5"), ":hatched_chick:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x90\xa6"), ":bird:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x90\xa7"), ":penguin:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x95\x8a"), ":dove:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa6\x85"), ":eagle:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa6\x86"), ":duck:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa6\x89"), ":owl:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x90\xb8"), ":frog:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x90\x8a"), ":crocodile:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x90\xa2"), ":turtle:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa6\x8e"), ":lizard:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x90\x8d"), ":snake:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x90\xb2"), ":dragon_face:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x90\x89"), ":dragon:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x90\xb3"), ":whale:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x90\x8b"), ":whale2:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x90\xac"), ":dolphin:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x90\x9f"), ":fish:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x90\xa0"), ":tropical_fish:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x90\xa1"), ":blowfish:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa6\x88"), ":shark:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x90\x99"), ":octopus:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x90\x9a"), ":shell:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa6\x80"), ":crab:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa6\x90"), ":shrimp:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa6\x91"), ":squid:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa6\x8b"), ":butterfly:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x90\x8c"), ":snail:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x90\x9b"), ":bug:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x90\x9c"), ":ant:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x90\x9d"), ":bee:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x90\x9e"), ":beetle:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x95\xb7"), ":spider:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x95\xb8"), ":spider_web:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa6\x82"), ":scorpion:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x92\x90"), ":bouquet:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8c\xb8"), ":cherry_blossom:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\xb5"), ":rosette:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8c\xb9"), ":rose:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa5\x80"), ":wilted_rose:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8c\xba"), ":hibiscus:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8c\xbb"), ":sunflower:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8c\xbc"), ":blossom:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8c\xb7"), ":tulip:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8c\xb1"), ":seedling:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8c\xb2"), ":evergreen_tree:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8c\xb3"), ":deciduous_tree:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8c\xb4"), ":palm_tree:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8c\xb5"), ":cactus:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8c\xbe"), ":ear_of_rice:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8c\xbf"), ":herb:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x98\x98"), ":shamrock:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8d\x80"), ":four_leaf_clover:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8d\x81"), ":maple_leaf:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8d\x82"), ":fallen_leaf:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8d\x83"), ":leaves:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8d\x84"), ":mushroom:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8c\xb0"), ":chestnut:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8c\x8d"), ":earth_africa:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8c\x8e"), ":earth_americas:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8c\x8f"), ":earth_asia:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8c\x91"), ":new_moon:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8c\x92"), ":waxing_crescent_moon:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8c\x93"), ":first_quarter_moon:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8c\x94"), ":waxing_gibbous_moon:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8c\x95"), ":full_moon:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8c\x96"), ":waning_gibbous_moon:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8c\x97"), ":last_quarter_moon:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8c\x98"), ":waning_crescent_moon:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8c\x99"), ":crescent_moon:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8c\x9a"), ":new_moon_with_face:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8c\x9b"), ":first_quarter_moon_with_face:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8c\x9c"), ":last_quarter_moon_with_face:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x98\x80"), ":sunny:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8c\x9d"), ":full_moon_with_face:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8c\x9e"), ":sun_with_face:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\xad\x90"), ":star:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8c\x9f"), ":star2:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x98\x81"), ":cloud:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9b\x85"), ":partly_sunny:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9b\x88"), ":thunder_cloud_rain:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8c\xa4"), ":white_sun_small_cloud:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8c\xa5"), ":white_sun_cloud:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8c\xa6"), ":white_sun_rain_cloud:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8c\xa7"), ":cloud_rain:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8c\xa8"), ":cloud_snow:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8c\xa9"), ":cloud_lightning:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8c\xaa"), ":cloud_tornado:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8c\xab"), ":fog:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8c\xac"), ":wind_blowing_face:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x98\x82"), ":umbrella2:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x98\x94"), ":umbrella:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9a\xa1"), ":zap:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9d\x84"), ":snowflake:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x98\x83"), ":snowman2:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9b\x84"), ":snowman:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x98\x84"), ":comet:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x94\xa5"), ":fire:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x92\xa7"), ":droplet:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8c\x8a"), ":ocean:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8e\x83"), ":jack_o_lantern:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8e\x84"), ":christmas_tree:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9c\xa8"), ":sparkles:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8e\x8b"), ":tanabata_tree:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8e\x8d"), ":bamboo:" }),
+};
+
+const QVariantList EmojiModel::food = {
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8d\x87"), ":grapes:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8d\x88"), ":melon:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8d\x89"), ":watermelon:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8d\x8a"), ":tangerine:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8d\x8b"), ":lemon:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8d\x8c"), ":banana:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8d\x8d"), ":pineapple:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8d\x8e"), ":apple:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8d\x8f"), ":green_apple:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8d\x90"), ":pear:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8d\x91"), ":peach:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8d\x92"), ":cherries:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8d\x93"), ":strawberry:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa5\x9d"), ":kiwi:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8d\x85"), ":tomato:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa5\x91"), ":avocado:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8d\x86"), ":eggplant:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa5\x94"), ":potato:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa5\x95"), ":carrot:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8c\xbd"), ":corn:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8c\xb6"), ":hot_pepper:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa5\x92"), ":cucumber:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa5\x9c"), ":peanuts:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8d\x9e"), ":bread:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa5\x90"), ":croissant:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa5\x96"), ":french_bread:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa5\x9e"), ":pancakes:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa7\x80"), ":cheese:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8d\x96"), ":meat_on_bone:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8d\x97"), ":poultry_leg:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa5\x93"), ":bacon:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8d\x94"), ":hamburger:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8d\x9f"), ":fries:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8d\x95"), ":pizza:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8c\xad"), ":hotdog:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8c\xae"), ":taco:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8c\xaf"), ":burrito:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa5\x99"), ":stuffed_flatbread:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa5\x9a"), ":egg:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8d\xb3"), ":cooking:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa5\x98"), ":shallow_pan_of_food:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8d\xb2"), ":stew:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa5\x97"), ":salad:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8d\xbf"), ":popcorn:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8d\xb1"), ":bento:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8d\x98"), ":rice_cracker:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8d\x99"), ":rice_ball:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8d\x9a"), ":rice:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8d\x9b"), ":curry:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8d\x9c"), ":ramen:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8d\x9d"), ":spaghetti:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8d\xa0"), ":sweet_potato:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8d\xa2"), ":oden:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8d\xa3"), ":sushi:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8d\xa4"), ":fried_shrimp:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8d\xa5"), ":fish_cake:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8d\xa1"), ":dango:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8d\xa6"), ":icecream:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8d\xa7"), ":shaved_ice:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8d\xa8"), ":ice_cream:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8d\xa9"), ":doughnut:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8d\xaa"), ":cookie:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8e\x82"), ":birthday:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8d\xb0"), ":cake:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8d\xab"), ":chocolate_bar:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8d\xac"), ":candy:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8d\xad"), ":lollipop:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8d\xae"), ":custard:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8d\xaf"), ":honey_pot:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8d\xbc"), ":baby_bottle:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa5\x9b"), ":milk:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x98\x95"), ":coffee:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8d\xb5"), ":tea:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8d\xb6"), ":sake:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8d\xbe"), ":champagne:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8d\xb7"), ":wine_glass:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8d\xb8"), ":cocktail:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8d\xb9"), ":tropical_drink:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8d\xba"), ":beer:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8d\xbb"), ":beers:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa5\x82"), ":champagne_glass:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa5\x83"), ":tumbler_glass:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8d\xbd"), ":fork_knife_plate:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8d\xb4"), ":fork_and_knife:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa5\x84"), ":spoon:" }),
+};
+
+const QVariantList EmojiModel::activity = {
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x91\xbe"), ":space_invader:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x95\xb4"), ":levitate:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa4\xba"), ":fencer:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\x87"), ":horse_racing:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\x87\xf0\x9f\x8f\xbb"), ":horse_racing_tone1:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\x87\xf0\x9f\x8f\xbc"), ":horse_racing_tone2:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\x87\xf0\x9f\x8f\xbd"), ":horse_racing_tone3:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\x87\xf0\x9f\x8f\xbe"), ":horse_racing_tone4:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\x87\xf0\x9f\x8f\xbf"), ":horse_racing_tone5:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9b\xb7"), ":skier:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\x82"), ":snowboarder:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\x8c"), ":golfer:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\x84"), ":surfer:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\x84\xf0\x9f\x8f\xbb"), ":surfer_tone1:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\x84\xf0\x9f\x8f\xbc"), ":surfer_tone2:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\x84\xf0\x9f\x8f\xbd"), ":surfer_tone3:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\x84\xf0\x9f\x8f\xbe"), ":surfer_tone4:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\x84\xf0\x9f\x8f\xbf"), ":surfer_tone5:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\xa3"), ":rowboat:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\xa3\xf0\x9f\x8f\xbb"), ":rowboat_tone1:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\xa3\xf0\x9f\x8f\xbc"), ":rowboat_tone2:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\xa3\xf0\x9f\x8f\xbd"), ":rowboat_tone3:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\xa3\xf0\x9f\x8f\xbe"), ":rowboat_tone4:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\xa3\xf0\x9f\x8f\xbf"), ":rowboat_tone5:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\x8a"), ":swimmer:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\x8a\xf0\x9f\x8f\xbb"), ":swimmer_tone1:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\x8a\xf0\x9f\x8f\xbc"), ":swimmer_tone2:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\x8a\xf0\x9f\x8f\xbd"), ":swimmer_tone3:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\x8a\xf0\x9f\x8f\xbe"), ":swimmer_tone4:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\x8a\xf0\x9f\x8f\xbf"), ":swimmer_tone5:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9b\xb9"), ":basketball_player:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9b\xb9\xf0\x9f\x8f\xbb"), ":basketball_player_tone1:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9b\xb9\xf0\x9f\x8f\xbc"), ":basketball_player_tone2:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9b\xb9\xf0\x9f\x8f\xbd"), ":basketball_player_tone3:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9b\xb9\xf0\x9f\x8f\xbe"), ":basketball_player_tone4:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9b\xb9\xf0\x9f\x8f\xbf"), ":basketball_player_tone5:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\x8b"), ":lifter:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\x8b\xf0\x9f\x8f\xbb"), ":lifter_tone1:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\x8b\xf0\x9f\x8f\xbc"), ":lifter_tone2:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\x8b\xf0\x9f\x8f\xbd"), ":lifter_tone3:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\x8b\xf0\x9f\x8f\xbe"), ":lifter_tone4:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\x8b\xf0\x9f\x8f\xbf"), ":lifter_tone5:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\xb4"), ":bicyclist:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\xb4\xf0\x9f\x8f\xbb"), ":bicyclist_tone1:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\xb4\xf0\x9f\x8f\xbc"), ":bicyclist_tone2:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\xb4\xf0\x9f\x8f\xbd"), ":bicyclist_tone3:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\xb4\xf0\x9f\x8f\xbe"), ":bicyclist_tone4:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\xb4\xf0\x9f\x8f\xbf"), ":bicyclist_tone5:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\xb5"), ":mountain_bicyclist:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\xb5\xf0\x9f\x8f\xbb"), ":mountain_bicyclist_tone1:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\xb5\xf0\x9f\x8f\xbc"), ":mountain_bicyclist_tone2:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\xb5\xf0\x9f\x8f\xbd"), ":mountain_bicyclist_tone3:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\xb5\xf0\x9f\x8f\xbe"), ":mountain_bicyclist_tone4:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\xb5\xf0\x9f\x8f\xbf"), ":mountain_bicyclist_tone5:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa4\xb8"), ":cartwheel:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa4\xb8\xf0\x9f\x8f\xbb"), ":cartwheel_tone1:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa4\xb8\xf0\x9f\x8f\xbc"), ":cartwheel_tone2:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa4\xb8\xf0\x9f\x8f\xbd"), ":cartwheel_tone3:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa4\xb8\xf0\x9f\x8f\xbe"), ":cartwheel_tone4:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa4\xb8\xf0\x9f\x8f\xbf"), ":cartwheel_tone5:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa4\xbc"), ":wrestlers:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa4\xbc\xf0\x9f\x8f\xbb"), ":wrestlers_tone1:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa4\xbc\xf0\x9f\x8f\xbc"), ":wrestlers_tone2:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa4\xbc\xf0\x9f\x8f\xbd"), ":wrestlers_tone3:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa4\xbc\xf0\x9f\x8f\xbe"), ":wrestlers_tone4:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa4\xbc\xf0\x9f\x8f\xbf"), ":wrestlers_tone5:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa4\xbd"), ":water_polo:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa4\xbd\xf0\x9f\x8f\xbb"), ":water_polo_tone1:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa4\xbd\xf0\x9f\x8f\xbc"), ":water_polo_tone2:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa4\xbd\xf0\x9f\x8f\xbd"), ":water_polo_tone3:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa4\xbd\xf0\x9f\x8f\xbe"), ":water_polo_tone4:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa4\xbd\xf0\x9f\x8f\xbf"), ":water_polo_tone5:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa4\xbe"), ":handball:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa4\xbe\xf0\x9f\x8f\xbb"), ":handball_tone1:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa4\xbe\xf0\x9f\x8f\xbc"), ":handball_tone2:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa4\xbe\xf0\x9f\x8f\xbd"), ":handball_tone3:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa4\xbe\xf0\x9f\x8f\xbe"), ":handball_tone4:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa4\xbe\xf0\x9f\x8f\xbf"), ":handball_tone5:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa4\xb9"), ":juggling:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa4\xb9\xf0\x9f\x8f\xbb"), ":juggling_tone1:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa4\xb9\xf0\x9f\x8f\xbc"), ":juggling_tone2:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa4\xb9\xf0\x9f\x8f\xbd"), ":juggling_tone3:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa4\xb9\xf0\x9f\x8f\xbe"), ":juggling_tone4:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa4\xb9\xf0\x9f\x8f\xbf"), ":juggling_tone5:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8e\xaa"), ":circus_tent:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8e\xad"), ":performing_arts:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8e\xa8"), ":art:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8e\xb0"), ":slot_machine:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9b\x80"), ":bath:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9b\x80\xf0\x9f\x8f\xbb"), ":bath_tone1:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9b\x80\xf0\x9f\x8f\xbc"), ":bath_tone2:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9b\x80\xf0\x9f\x8f\xbd"), ":bath_tone3:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9b\x80\xf0\x9f\x8f\xbe"), ":bath_tone4:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9b\x80\xf0\x9f\x8f\xbf"), ":bath_tone5:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8e\x97"), ":reminder_ribbon:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8e\x9f"), ":tickets:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8e\xab"), ":ticket:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8e\x96"), ":military_medal:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\x86"), ":trophy:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\x85"), ":medal:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa5\x87"), ":first_place:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa5\x88"), ":second_place:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa5\x89"), ":third_place:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9a\xbd"), ":soccer:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9a\xbe"), ":baseball:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\x80"), ":basketball:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\x90"), ":volleyball:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\x88"), ":football:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\x89"), ":rugby_football:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8e\xbe"), ":tennis:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8e\xb1"), ":8ball:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8e\xb3"), ":bowling:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\x8f"), ":cricket:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\x91"), ":field_hockey:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\x92"), ":hockey:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\x93"), ":ping_pong:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\xb8"), ":badminton:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa5\x8a"), ":boxing_glove:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa5\x8b"), ":martial_arts_uniform:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa5\x85"), ":goal:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8e\xaf"), ":dart:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9b\xb3"), ":golf:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9b\xb8"), ":ice_skate:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8e\xa3"), ":fishing_pole_and_fish:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8e\xbd"), ":running_shirt_with_sash:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8e\xbf"), ":ski:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8e\xae"), ":video_game:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8e\xb2"), ":game_die:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8e\xbc"), ":musical_score:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8e\xa4"), ":microphone:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8e\xa7"), ":headphones:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8e\xb7"), ":saxophone:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8e\xb8"), ":guitar:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8e\xb9"), ":musical_keyboard:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8e\xba"), ":trumpet:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8e\xbb"), ":violin:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\xa5\x81"), ":drum:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8e\xac"), ":clapper:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\xb9"), ":bow_and_arrow:" }),
+};
+
+const QVariantList EmojiModel::travel = {
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\x8e"), ":race_car:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\x8d"), ":motorcycle:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x97\xbe"), ":japan:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\x94"), ":mountain_snow:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9b\xb0"), ":mountain:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8c\x8b"), ":volcano:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x97\xbb"), ":mount_fuji:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\x95"), ":camping:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\x96"), ":beach:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\x9c"), ":desert:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\x9d"), ":island:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\x9e"), ":park:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\x9f"), ":stadium:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\x9b"), ":classical_building:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\x97"), ":construction_site:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\x98"), ":homes:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\x99"), ":cityscape:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\x9a"), ":house_abandoned:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\xa0"), ":house:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\xa1"), ":house_with_garden:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\xa2"), ":office:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\xa3"), ":post_office:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\xa4"), ":european_post_office:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\xa5"), ":hospital:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\xa6"), ":bank:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\xa8"), ":hotel:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\xa9"), ":love_hotel:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\xaa"), ":convenience_store:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\xab"), ":school:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\xac"), ":department_store:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\xad"), ":factory:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\xaf"), ":japanese_castle:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\xb0"), ":european_castle:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x92\x92"), ":wedding:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x97\xbc"), ":tokyo_tower:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x97\xbd"), ":statue_of_liberty:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9b\xaa"), ":church:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x95\x8c"), ":mosque:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x95\x8d"), ":synagogue:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9b\xa9"), ":shinto_shrine:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x95\x8b"), ":kaaba:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9b\xb2"), ":fountain:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9b\xba"), ":tent:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8c\x81"), ":foggy:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8c\x83"), ":night_with_stars:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8c\x84"), ":sunrise_over_mountains:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8c\x85"), ":sunrise:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8c\x86"), ":city_dusk:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8c\x87"), ":city_sunset:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8c\x89"), ":bridge_at_night:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8c\x8c"), ":milky_way:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8e\xa0"), ":carousel_horse:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8e\xa1"), ":ferris_wheel:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8e\xa2"), ":roller_coaster:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\x82"), ":steam_locomotive:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\x83"), ":railway_car:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\x84"), ":bullettrain_side:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\x85"), ":bullettrain_front:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\x86"), ":train2:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\x87"), ":metro:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\x88"), ":light_rail:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\x89"), ":station:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\x8a"), ":tram:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\x9d"), ":monorail:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\x9e"), ":mountain_railway:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\x8b"), ":train:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\x8c"), ":bus:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\x8d"), ":oncoming_bus:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\x8e"), ":trolleybus:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\x90"), ":minibus:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\x91"), ":ambulance:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\x92"), ":fire_engine:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\x93"), ":police_car:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\x94"), ":oncoming_police_car:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\x95"), ":taxi:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\x96"), ":oncoming_taxi:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\x97"), ":red_car:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\x98"), ":oncoming_automobile:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\x99"), ":blue_car:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\x9a"), ":truck:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\x9b"), ":articulated_lorry:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\x9c"), ":tractor:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\xb2"), ":bike:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9b\xb4"), ":scooter:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9b\xb5"), ":motor_scooter:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\x8f"), ":busstop:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9b\xa3"), ":motorway:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9b\xa4"), ":railway_track:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9b\xbd"), ":fuelpump:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\xa8"), ":rotating_light:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\xa5"), ":traffic_light:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\xa6"), ":vertical_traffic_light:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\xa7"), ":construction:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9a\x93"), ":anchor:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9b\xb5"), ":sailboat:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9b\xb6"), ":canoe:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\xa4"), ":speedboat:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9b\xb3"), ":cruise_ship:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9b\xb4"), ":ferry:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9b\xa5"), ":motorboat:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\xa2"), ":ship:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9c\x88"), ":airplane:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9b\xa9"), ":airplane_small:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9b\xab"), ":airplane_departure:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9b\xac"), ":airplane_arriving:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x92\xba"), ":seat:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\x81"), ":helicopter:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\x9f"), ":suspension_railway:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\xa0"), ":mountain_cableway:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\xa1"), ":aerial_tramway:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\x80"), ":rocket:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9b\xb0"), ":satellite_orbital:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8c\xa0"), ":stars:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8c\x88"), ":rainbow:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8e\x86"), ":fireworks:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8e\x87"), ":sparkler:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8e\x91"), ":rice_scene:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\x81"), ":checkered_flag:" }),
+};
+
+const QVariantList EmojiModel::objects = {
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x98\xa0"), ":skull_crossbones:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x92\x8c"), ":love_letter:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x92\xa3"), ":bomb:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x95\xb3"), ":hole:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9b\x8d"), ":shopping_bags:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x93\xbf"), ":prayer_beads:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x92\x8e"), ":gem:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x94\xaa"), ":knife:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\xba"), ":amphora:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x97\xba"), ":map:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x92\x88"), ":barber:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x96\xbc"), ":frame_photo:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9b\x8e"), ":bellhop:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\xaa"), ":door:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9b\x8c"), ":sleeping_accommodation:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9b\x8f"), ":bed:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9b\x8b"), ":couch:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\xbd"), ":toilet:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\xbf"), ":shower:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9b\x81"), ":bathtub:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x8c\x9b"), ":hourglass:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x8f\xb3"), ":hourglass_flowing_sand:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x8c\x9a"), ":watch:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x8f\xb0"), ":alarm_clock:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x8f\xb1"), ":stopwatch:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x8f\xb2"), ":timer:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x95\xb0"), ":clock:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8c\xa1"), ":thermometer:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9b\xb1"), ":beach_umbrella:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8e\x88"), ":balloon:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8e\x89"), ":tada:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8e\x8a"), ":confetti_ball:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8e\x8e"), ":dolls:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8e\x8f"), ":flags:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8e\x90"), ":wind_chime:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8e\x80"), ":ribbon:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8e\x81"), ":gift:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x95\xb9"), ":joystick:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x93\xaf"), ":postal_horn:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8e\x99"), ":microphone2:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8e\x9a"), ":level_slider:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8e\x9b"), ":control_knobs:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x93\xbb"), ":radio:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x93\xb1"), ":iphone:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x93\xb2"), ":calling:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x98\x8e"), ":telephone:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x93\x9e"), ":telephone_receiver:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x93\x9f"), ":pager:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x93\xa0"), ":fax:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x94\x8b"), ":battery:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x94\x8c"), ":electric_plug:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x92\xbb"), ":computer:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x96\xa5"), ":desktop:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x96\xa8"), ":printer:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x8c\xa8"), ":keyboard:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x96\xb1"), ":mouse_three_button:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x96\xb2"), ":trackball:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x92\xbd"), ":minidisc:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x92\xbe"), ":floppy_disk:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x92\xbf"), ":cd:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x93\x80"), ":dvd:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8e\xa5"), ":movie_camera:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8e\x9e"), ":film_frames:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x93\xbd"), ":projector:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x93\xba"), ":tv:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x93\xb7"), ":camera:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x93\xb8"), ":camera_with_flash:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x93\xb9"), ":video_camera:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x93\xbc"), ":vhs:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x94\x8d"), ":mag:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x94\x8e"), ":mag_right:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x94\xac"), ":microscope:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x94\xad"), ":telescope:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x93\xa1"), ":satellite:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x95\xaf"), ":candle:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x92\xa1"), ":bulb:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x94\xa6"), ":flashlight:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\xae"), ":izakaya_lantern:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x93\x94"), ":notebook_with_decorative_cover:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x93\x95"), ":closed_book:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x93\x96"), ":book:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x93\x97"), ":green_book:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x93\x98"), ":blue_book:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x93\x99"), ":orange_book:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x93\x9a"), ":books:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x93\x93"), ":notebook:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x93\x92"), ":ledger:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x93\x83"), ":page_with_curl:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x93\x9c"), ":scroll:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x93\x84"), ":page_facing_up:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x93\xb0"), ":newspaper:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x97\x9e"), ":newspaper2:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x93\x91"), ":bookmark_tabs:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x94\x96"), ":bookmark:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\xb7"), ":label:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x92\xb0"), ":moneybag:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x92\xb4"), ":yen:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x92\xb5"), ":dollar:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x92\xb6"), ":euro:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x92\xb7"), ":pound:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x92\xb8"), ":money_with_wings:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x92\xb3"), ":credit_card:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9c\x89"), ":envelope:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x93\xa7"), ":e-mail:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x93\xa8"), ":incoming_envelope:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x93\xa9"), ":envelope_with_arrow:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x93\xa4"), ":outbox_tray:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x93\xa5"), ":inbox_tray:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x93\xa6"), ":package:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x93\xab"), ":mailbox:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x93\xaa"), ":mailbox_closed:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x93\xac"), ":mailbox_with_mail:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x93\xad"), ":mailbox_with_no_mail:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x93\xae"), ":postbox:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x97\xb3"), ":ballot_box:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9c\x8f"), ":pencil2:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9c\x92"), ":black_nib:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x96\x8b"), ":pen_fountain:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x96\x8a"), ":pen_ballpoint:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x96\x8c"), ":paintbrush:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x96\x8d"), ":crayon:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x93\x9d"), ":pencil:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x93\x81"), ":file_folder:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x93\x82"), ":open_file_folder:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x97\x82"), ":dividers:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x93\x85"), ":date:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x93\x86"), ":calendar:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x97\x92"), ":notepad_spiral:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x97\x93"), ":calendar_spiral:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x93\x87"), ":card_index:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x93\x88"), ":chart_with_upwards_trend:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x93\x89"), ":chart_with_downwards_trend:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x93\x8a"), ":bar_chart:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x93\x8b"), ":clipboard:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x93\x8c"), ":pushpin:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x93\x8d"), ":round_pushpin:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x93\x8e"), ":paperclip:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x96\x87"), ":paperclips:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x93\x8f"), ":straight_ruler:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x93\x90"), ":triangular_ruler:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9c\x82"), ":scissors:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x97\x83"), ":card_box:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x97\x84"), ":file_cabinet:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x97\x91"), ":wastebasket:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x94\x92"), ":lock:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x94\x93"), ":unlock:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x94\x8f"), ":lock_with_ink_pen:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x94\x90"), ":closed_lock_with_key:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x94\x91"), ":key:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x97\x9d"), ":key2:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x94\xa8"), ":hammer:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9b\x8f"), ":pick:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9a\x92"), ":hammer_pick:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9b\xa0"), ":tools:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x97\xa1"), ":dagger:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9a\x94"), ":crossed_swords:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x94\xab"), ":gun:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9b\xa1"), ":shield:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x94\xa7"), ":wrench:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x94\xa9"), ":nut_and_bolt:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9a\x99"), ":gear:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x97\x9c"), ":compression:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9a\x97"), ":alembic:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9a\x96"), ":scales:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x94\x97"), ":link:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9b\x93"), ":chains:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x92\x89"), ":syringe:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x92\x8a"), ":pill:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\xac"), ":smoking:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9a\xb0"), ":coffin:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9a\xb1"), ":urn:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x97\xbf"), ":moyai:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9b\xa2"), ":oil:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x94\xae"), ":crystal_ball:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9b\x92"), ":shopping_cart:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\xa9"), ":triangular_flag_on_post:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8e\x8c"), ":crossed_flags:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\xb4"), ":flag_black:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\xb3"), ":flag_white:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\xb3\xf0\x9f\x8c\x88"), ":rainbow_flag:" }),
+};
+
+const QVariantList EmojiModel::symbols = {
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x91\x81\xf0\x9f\x97\xa8"), ":eye_in_speech_bubble:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x92\x98"), ":cupid:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9d\xa4"), ":heart:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x92\x93"), ":heartbeat:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x92\x94"), ":broken_heart:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x92\x95"), ":two_hearts:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x92\x96"), ":sparkling_heart:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x92\x97"), ":heartpulse:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x92\x99"), ":blue_heart:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x92\x9a"), ":green_heart:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x92\x9b"), ":yellow_heart:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x92\x9c"), ":purple_heart:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x96\xa4"), ":black_heart:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x92\x9d"), ":gift_heart:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x92\x9e"), ":revolving_hearts:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x92\x9f"), ":heart_decoration:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9d\xa3"), ":heart_exclamation:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x92\xa2"), ":anger:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x92\xa5"), ":boom:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x92\xab"), ":dizzy:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x92\xac"), ":speech_balloon:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x97\xa8"), ":speech_left:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x97\xaf"), ":anger_right:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x92\xad"), ":thought_balloon:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x92\xae"), ":white_flower:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8c\x90"), ":globe_with_meridians:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x99\xa8"), ":hotsprings:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9b\x91"), ":octagonal_sign:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x95\x9b"), ":clock12:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x95\xa7"), ":clock1230:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x95\x90"), ":clock1:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x95\x9c"), ":clock130:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x95\x91"), ":clock2:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x95\x9d"), ":clock230:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x95\x92"), ":clock3:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x95\x9e"), ":clock330:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x95\x93"), ":clock4:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x95\x9f"), ":clock430:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x95\x94"), ":clock5:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x95\xa0"), ":clock530:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x95\x95"), ":clock6:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x95\xa1"), ":clock630:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x95\x96"), ":clock7:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x95\xa2"), ":clock730:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x95\x97"), ":clock8:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x95\xa3"), ":clock830:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x95\x98"), ":clock9:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x95\xa4"), ":clock930:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x95\x99"), ":clock10:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x95\xa5"), ":clock1030:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x95\x9a"), ":clock11:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x95\xa6"), ":clock1130:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8c\x80"), ":cyclone:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x99\xa0"), ":spades:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x99\xa5"), ":hearts:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x99\xa6"), ":diamonds:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x99\xa3"), ":clubs:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x83\x8f"), ":black_joker:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x80\x84"), ":mahjong:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8e\xb4"), ":flower_playing_cards:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x94\x87"), ":mute:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x94\x88"), ":speaker:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x94\x89"), ":sound:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x94\x8a"), ":loud_sound:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x93\xa2"), ":loudspeaker:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x93\xa3"), ":mega:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x94\x94"), ":bell:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x94\x95"), ":no_bell:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8e\xb5"), ":musical_note:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8e\xb6"), ":notes:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x92\xb9"), ":chart:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x92\xb1"), ":currency_exchange:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x92\xb2"), ":heavy_dollar_sign:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8f\xa7"), ":atm:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\xae"), ":put_litter_in_its_place:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\xb0"), ":potable_water:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x99\xbf"), ":wheelchair:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\xb9"), ":mens:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\xba"), ":womens:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\xbb"), ":restroom:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\xbc"), ":baby_symbol:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\xbe"), ":wc:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9b\x82"), ":passport_control:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9b\x83"), ":customs:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9b\x84"), ":baggage_claim:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9b\x85"), ":left_luggage:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9a\xa0"), ":warning:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\xb8"), ":children_crossing:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9b\x94"), ":no_entry:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\xab"), ":no_entry_sign:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\xb3"), ":no_bicycles:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\xad"), ":no_smoking:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\xaf"), ":do_not_litter:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\xb1"), ":non-potable_water:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9a\xb7"), ":no_pedestrians:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x93\xb5"), ":no_mobile_phones:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x94\x9e"), ":underage:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x98\xa2"), ":radioactive:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x98\xa3"), ":biohazard:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\xac\x86"), ":arrow_up:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x86\x97"), ":arrow_upper_right:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9e\xa1"), ":arrow_right:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x86\x98"), ":arrow_lower_right:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\xac\x87"), ":arrow_down:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x86\x99"), ":arrow_lower_left:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\xac\x85"), ":arrow_left:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x86\x96"), ":arrow_upper_left:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x86\x95"), ":arrow_up_down:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x86\x94"), ":left_right_arrow:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x86\xa9"), ":leftwards_arrow_with_hook:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x86\xaa"), ":arrow_right_hook:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\xa4\xb4"), ":arrow_heading_up:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\xa4\xb5"), ":arrow_heading_down:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x94\x83"), ":arrows_clockwise:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x94\x84"), ":arrows_counterclockwise:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x94\x99"), ":back:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x94\x9a"), ":end:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x94\x9b"), ":on:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x94\x9c"), ":soon:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x94\x9d"), ":top:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x9b\x90"), ":place_of_worship:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9a\x9b"), ":atom:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x95\x89"), ":om_symbol:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9c\xa1"), ":star_of_david:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x98\xb8"), ":wheel_of_dharma:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x98\xaf"), ":yin_yang:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9c\x9d"), ":cross:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x98\xa6"), ":orthodox_cross:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x98\xaa"), ":star_and_crescent:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x98\xae"), ":peace:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x95\x8e"), ":menorah:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x94\xaf"), ":six_pointed_star:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x99\x88"), ":aries:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x99\x89"), ":taurus:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x99\x8a"), ":gemini:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x99\x8b"), ":cancer:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x99\x8c"), ":leo:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x99\x8d"), ":virgo:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x99\x8e"), ":libra:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x99\x8f"), ":scorpius:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x99\x90"), ":sagittarius:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x99\x91"), ":capricorn:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x99\x92"), ":aquarius:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x99\x93"), ":pisces:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9b\x8e"), ":ophiuchus:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x94\x80"), ":twisted_rightwards_arrows:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x94\x81"), ":repeat:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x94\x82"), ":repeat_one:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x96\xb6"), ":arrow_forward:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x8f\xa9"), ":fast_forward:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x8f\xad"), ":track_next:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x8f\xaf"), ":play_pause:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x97\x80"), ":arrow_backward:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x8f\xaa"), ":rewind:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x8f\xae"), ":track_previous:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x94\xbc"), ":arrow_up_small:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x8f\xab"), ":arrow_double_up:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x94\xbd"), ":arrow_down_small:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x8f\xac"), ":arrow_double_down:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x8f\xb8"), ":pause_button:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x8f\xb9"), ":stop_button:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x8f\xba"), ":record_button:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x8f\x8f"), ":eject:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x8e\xa6"), ":cinema:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x94\x85"), ":low_brightness:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x94\x86"), ":high_brightness:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x93\xb6"), ":signal_strength:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x93\xb3"), ":vibration_mode:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x93\xb4"), ":mobile_phone_off:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x99\xbb"), ":recycle:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x93\x9b"), ":name_badge:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9a\x9c"), ":fleur-de-lis:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x94\xb0"), ":beginner:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x94\xb1"), ":trident:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\xad\x95"), ":o:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9c\x85"), ":white_check_mark:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x98\x91"), ":ballot_box_with_check:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9c\x94"), ":heavy_check_mark:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9c\x96"), ":heavy_multiplication_x:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9d\x8c"), ":x:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9d\x8e"), ":negative_squared_cross_mark:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9e\x95"), ":heavy_plus_sign:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9e\x96"), ":heavy_minus_sign:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9e\x97"), ":heavy_division_sign:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9e\xb0"), ":curly_loop:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9e\xbf"), ":loop:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe3\x80\xbd"), ":part_alternation_mark:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9c\xb3"), ":eight_spoked_asterisk:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9c\xb4"), ":eight_pointed_black_star:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9d\x87"), ":sparkle:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x80\xbc"), ":bangbang:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x81\x89"), ":interrobang:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9d\x93"), ":question:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9d\x94"), ":grey_question:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9d\x95"), ":grey_exclamation:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9d\x97"), ":exclamation:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe3\x80\xb0"), ":wavy_dash:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xc2\xa9"), ":copyright:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xc2\xae"), ":registered:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x84\xa2"), ":tm:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("#\xe2\x83\xa3"), ":hash:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("*\xe2\x83\xa3"), ":asterisk:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("0\xe2\x83\xa3"), ":zero:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("1\xe2\x83\xa3"), ":one:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("2\xe2\x83\xa3"), ":two:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("3\xe2\x83\xa3"), ":three:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("4\xe2\x83\xa3"), ":four:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("5\xe2\x83\xa3"), ":five:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("6\xe2\x83\xa3"), ":six:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("7\xe2\x83\xa3"), ":seven:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("8\xe2\x83\xa3"), ":eight:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("9\xe2\x83\xa3"), ":nine:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x94\x9f"), ":keycap_ten:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x92\xaf"), ":100:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x94\xa0"), ":capital_abcd:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x94\xa1"), ":abcd:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x94\xa2"), ":1234:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x94\xa3"), ":symbols:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x94\xa4"), ":abc:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x85\xb0"), ":a:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x86\x8e"), ":ab:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x85\xb1"), ":b:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x86\x91"), ":cl:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x86\x92"), ":cool:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x86\x93"), ":free:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x84\xb9"), ":information_source:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x86\x94"), ":id:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x93\x82"), ":m:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x86\x95"), ":new:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x86\x96"), ":ng:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x85\xbe"), ":o2:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x86\x97"), ":ok:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x85\xbf"), ":parking:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x86\x98"), ":sos:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x86\x99"), ":up:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x86\x9a"), ":vs:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x88\x81"), ":koko:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x88\x82"), ":sa:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x88\xb7"), ":u6708:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x88\xb6"), ":u6709:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x88\xaf"), ":u6307:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x89\x90"), ":ideograph_advantage:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x88\xb9"), ":u5272:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x88\x9a"), ":u7121:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x88\xb2"), ":u7981:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x89\x91"), ":accept:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x88\xb8"), ":u7533:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x88\xb4"), ":u5408:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x88\xb3"), ":u7a7a:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe3\x8a\x97"), ":congratulations:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe3\x8a\x99"), ":secret:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x88\xba"), ":u55b6:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x88\xb5"), ":u6e80:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x96\xaa"), ":black_small_square:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x96\xab"), ":white_small_square:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x97\xbb"), ":white_medium_square:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x97\xbc"), ":black_medium_square:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x97\xbd"), ":white_medium_small_square:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x97\xbe"), ":black_medium_small_square:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\xac\x9b"), ":black_large_square:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\xac\x9c"), ":white_large_square:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x94\xb6"), ":large_orange_diamond:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x94\xb7"), ":large_blue_diamond:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x94\xb8"), ":small_orange_diamond:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x94\xb9"), ":small_blue_diamond:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x94\xba"), ":small_red_triangle:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x94\xbb"), ":small_red_triangle_down:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x92\xa0"), ":diamond_shape_with_a_dot_inside:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x94\x98"), ":radio_button:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x94\xb2"), ":black_square_button:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x94\xb3"), ":white_square_button:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9a\xaa"), ":white_circle:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xe2\x9a\xab"), ":black_circle:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x94\xb4"), ":red_circle:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x94\xb5"), ":blue_circle:" }),
+};
+
+const QVariantList EmojiModel::flags = {
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xa6\xf0\x9f\x87\xa8"), ":flag_ac:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xa6\xf0\x9f\x87\xa9"), ":flag_ad:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xa6\xf0\x9f\x87\xaa"), ":flag_ae:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xa6\xf0\x9f\x87\xab"), ":flag_af:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xa6\xf0\x9f\x87\xac"), ":flag_ag:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xa6\xf0\x9f\x87\xae"), ":flag_ai:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xa6\xf0\x9f\x87\xb1"), ":flag_al:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xa6\xf0\x9f\x87\xb2"), ":flag_am:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xa6\xf0\x9f\x87\xb4"), ":flag_ao:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xa6\xf0\x9f\x87\xb6"), ":flag_aq:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xa6\xf0\x9f\x87\xb7"), ":flag_ar:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xa6\xf0\x9f\x87\xb8"), ":flag_as:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xa6\xf0\x9f\x87\xb9"), ":flag_at:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xa6\xf0\x9f\x87\xba"), ":flag_au:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xa6\xf0\x9f\x87\xbc"), ":flag_aw:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xa6\xf0\x9f\x87\xbd"), ":flag_ax:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xa6\xf0\x9f\x87\xbf"), ":flag_az:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xa7\xf0\x9f\x87\xa6"), ":flag_ba:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xa7\xf0\x9f\x87\xa7"), ":flag_bb:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xa7\xf0\x9f\x87\xa9"), ":flag_bd:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xa7\xf0\x9f\x87\xaa"), ":flag_be:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xa7\xf0\x9f\x87\xab"), ":flag_bf:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xa7\xf0\x9f\x87\xac"), ":flag_bg:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xa7\xf0\x9f\x87\xad"), ":flag_bh:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xa7\xf0\x9f\x87\xae"), ":flag_bi:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xa7\xf0\x9f\x87\xaf"), ":flag_bj:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xa7\xf0\x9f\x87\xb1"), ":flag_bl:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xa7\xf0\x9f\x87\xb2"), ":flag_bm:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xa7\xf0\x9f\x87\xb3"), ":flag_bn:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xa7\xf0\x9f\x87\xb4"), ":flag_bo:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xa7\xf0\x9f\x87\xb6"), ":flag_bq:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xa7\xf0\x9f\x87\xb7"), ":flag_br:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xa7\xf0\x9f\x87\xb8"), ":flag_bs:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xa7\xf0\x9f\x87\xb9"), ":flag_bt:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xa7\xf0\x9f\x87\xbb"), ":flag_bv:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xa7\xf0\x9f\x87\xbc"), ":flag_bw:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xa7\xf0\x9f\x87\xbe"), ":flag_by:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xa7\xf0\x9f\x87\xbf"), ":flag_bz:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xa8\xf0\x9f\x87\xa6"), ":flag_ca:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xa8\xf0\x9f\x87\xa8"), ":flag_cc:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xa8\xf0\x9f\x87\xa9"), ":flag_cd:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xa8\xf0\x9f\x87\xab"), ":flag_cf:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xa8\xf0\x9f\x87\xac"), ":flag_cg:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xa8\xf0\x9f\x87\xad"), ":flag_ch:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xa8\xf0\x9f\x87\xae"), ":flag_ci:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xa8\xf0\x9f\x87\xb0"), ":flag_ck:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xa8\xf0\x9f\x87\xb1"), ":flag_cl:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xa8\xf0\x9f\x87\xb2"), ":flag_cm:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xa8\xf0\x9f\x87\xb3"), ":flag_cn:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xa8\xf0\x9f\x87\xb4"), ":flag_co:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xa8\xf0\x9f\x87\xb5"), ":flag_cp:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xa8\xf0\x9f\x87\xb7"), ":flag_cr:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xa8\xf0\x9f\x87\xba"), ":flag_cu:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xa8\xf0\x9f\x87\xbb"), ":flag_cv:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xa8\xf0\x9f\x87\xbc"), ":flag_cw:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xa8\xf0\x9f\x87\xbd"), ":flag_cx:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xa8\xf0\x9f\x87\xbe"), ":flag_cy:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xa8\xf0\x9f\x87\xbf"), ":flag_cz:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xa9\xf0\x9f\x87\xaa"), ":flag_de:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xa9\xf0\x9f\x87\xac"), ":flag_dg:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xa9\xf0\x9f\x87\xaf"), ":flag_dj:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xa9\xf0\x9f\x87\xb0"), ":flag_dk:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xa9\xf0\x9f\x87\xb2"), ":flag_dm:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xa9\xf0\x9f\x87\xb4"), ":flag_do:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xa9\xf0\x9f\x87\xbf"), ":flag_dz:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xaa\xf0\x9f\x87\xa6"), ":flag_ea:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xaa\xf0\x9f\x87\xa8"), ":flag_ec:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xaa\xf0\x9f\x87\xaa"), ":flag_ee:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xaa\xf0\x9f\x87\xac"), ":flag_eg:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xaa\xf0\x9f\x87\xad"), ":flag_eh:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xaa\xf0\x9f\x87\xb7"), ":flag_er:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xaa\xf0\x9f\x87\xb8"), ":flag_es:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xaa\xf0\x9f\x87\xb9"), ":flag_et:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xaa\xf0\x9f\x87\xba"), ":flag_eu:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xab\xf0\x9f\x87\xae"), ":flag_fi:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xab\xf0\x9f\x87\xaf"), ":flag_fj:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xab\xf0\x9f\x87\xb0"), ":flag_fk:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xab\xf0\x9f\x87\xb2"), ":flag_fm:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xab\xf0\x9f\x87\xb4"), ":flag_fo:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xab\xf0\x9f\x87\xb7"), ":flag_fr:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xac\xf0\x9f\x87\xa6"), ":flag_ga:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xac\xf0\x9f\x87\xa7"), ":flag_gb:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xac\xf0\x9f\x87\xa9"), ":flag_gd:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xac\xf0\x9f\x87\xaa"), ":flag_ge:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xac\xf0\x9f\x87\xab"), ":flag_gf:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xac\xf0\x9f\x87\xac"), ":flag_gg:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xac\xf0\x9f\x87\xad"), ":flag_gh:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xac\xf0\x9f\x87\xae"), ":flag_gi:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xac\xf0\x9f\x87\xb1"), ":flag_gl:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xac\xf0\x9f\x87\xb2"), ":flag_gm:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xac\xf0\x9f\x87\xb3"), ":flag_gn:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xac\xf0\x9f\x87\xb5"), ":flag_gp:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xac\xf0\x9f\x87\xb6"), ":flag_gq:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xac\xf0\x9f\x87\xb7"), ":flag_gr:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xac\xf0\x9f\x87\xb8"), ":flag_gs:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xac\xf0\x9f\x87\xb9"), ":flag_gt:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xac\xf0\x9f\x87\xba"), ":flag_gu:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xac\xf0\x9f\x87\xbc"), ":flag_gw:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xac\xf0\x9f\x87\xbe"), ":flag_gy:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xad\xf0\x9f\x87\xb0"), ":flag_hk:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xad\xf0\x9f\x87\xb2"), ":flag_hm:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xad\xf0\x9f\x87\xb3"), ":flag_hn:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xad\xf0\x9f\x87\xb7"), ":flag_hr:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xad\xf0\x9f\x87\xb9"), ":flag_ht:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xad\xf0\x9f\x87\xba"), ":flag_hu:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xae\xf0\x9f\x87\xa8"), ":flag_ic:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xae\xf0\x9f\x87\xa9"), ":flag_id:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xae\xf0\x9f\x87\xaa"), ":flag_ie:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xae\xf0\x9f\x87\xb1"), ":flag_il:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xae\xf0\x9f\x87\xb2"), ":flag_im:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xae\xf0\x9f\x87\xb3"), ":flag_in:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xae\xf0\x9f\x87\xb4"), ":flag_io:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xae\xf0\x9f\x87\xb6"), ":flag_iq:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xae\xf0\x9f\x87\xb7"), ":flag_ir:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xae\xf0\x9f\x87\xb8"), ":flag_is:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xae\xf0\x9f\x87\xb9"), ":flag_it:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xaf\xf0\x9f\x87\xaa"), ":flag_je:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xaf\xf0\x9f\x87\xb2"), ":flag_jm:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xaf\xf0\x9f\x87\xb4"), ":flag_jo:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xaf\xf0\x9f\x87\xb5"), ":flag_jp:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb0\xf0\x9f\x87\xaa"), ":flag_ke:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb0\xf0\x9f\x87\xac"), ":flag_kg:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb0\xf0\x9f\x87\xad"), ":flag_kh:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb0\xf0\x9f\x87\xae"), ":flag_ki:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb0\xf0\x9f\x87\xb2"), ":flag_km:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb0\xf0\x9f\x87\xb3"), ":flag_kn:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb0\xf0\x9f\x87\xb5"), ":flag_kp:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb0\xf0\x9f\x87\xb7"), ":flag_kr:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb0\xf0\x9f\x87\xbc"), ":flag_kw:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb0\xf0\x9f\x87\xbe"), ":flag_ky:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb0\xf0\x9f\x87\xbf"), ":flag_kz:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb1\xf0\x9f\x87\xa6"), ":flag_la:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb1\xf0\x9f\x87\xa7"), ":flag_lb:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb1\xf0\x9f\x87\xa8"), ":flag_lc:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb1\xf0\x9f\x87\xae"), ":flag_li:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb1\xf0\x9f\x87\xb0"), ":flag_lk:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb1\xf0\x9f\x87\xb7"), ":flag_lr:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb1\xf0\x9f\x87\xb8"), ":flag_ls:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb1\xf0\x9f\x87\xb9"), ":flag_lt:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb1\xf0\x9f\x87\xba"), ":flag_lu:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb1\xf0\x9f\x87\xbb"), ":flag_lv:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb1\xf0\x9f\x87\xbe"), ":flag_ly:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb2\xf0\x9f\x87\xa6"), ":flag_ma:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb2\xf0\x9f\x87\xa8"), ":flag_mc:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb2\xf0\x9f\x87\xa9"), ":flag_md:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb2\xf0\x9f\x87\xaa"), ":flag_me:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb2\xf0\x9f\x87\xab"), ":flag_mf:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb2\xf0\x9f\x87\xac"), ":flag_mg:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb2\xf0\x9f\x87\xad"), ":flag_mh:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb2\xf0\x9f\x87\xb0"), ":flag_mk:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb2\xf0\x9f\x87\xb1"), ":flag_ml:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb2\xf0\x9f\x87\xb2"), ":flag_mm:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb2\xf0\x9f\x87\xb3"), ":flag_mn:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb2\xf0\x9f\x87\xb4"), ":flag_mo:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb2\xf0\x9f\x87\xb5"), ":flag_mp:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb2\xf0\x9f\x87\xb6"), ":flag_mq:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb2\xf0\x9f\x87\xb7"), ":flag_mr:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb2\xf0\x9f\x87\xb8"), ":flag_ms:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb2\xf0\x9f\x87\xb9"), ":flag_mt:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb2\xf0\x9f\x87\xba"), ":flag_mu:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb2\xf0\x9f\x87\xbb"), ":flag_mv:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb2\xf0\x9f\x87\xbc"), ":flag_mw:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb2\xf0\x9f\x87\xbd"), ":flag_mx:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb2\xf0\x9f\x87\xbe"), ":flag_my:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb2\xf0\x9f\x87\xbf"), ":flag_mz:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb3\xf0\x9f\x87\xa6"), ":flag_na:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb3\xf0\x9f\x87\xa8"), ":flag_nc:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb3\xf0\x9f\x87\xaa"), ":flag_ne:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb3\xf0\x9f\x87\xab"), ":flag_nf:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb3\xf0\x9f\x87\xac"), ":flag_ng:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb3\xf0\x9f\x87\xae"), ":flag_ni:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb3\xf0\x9f\x87\xb1"), ":flag_nl:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb3\xf0\x9f\x87\xb4"), ":flag_no:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb3\xf0\x9f\x87\xb5"), ":flag_np:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb3\xf0\x9f\x87\xb7"), ":flag_nr:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb3\xf0\x9f\x87\xba"), ":flag_nu:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb3\xf0\x9f\x87\xbf"), ":flag_nz:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb4\xf0\x9f\x87\xb2"), ":flag_om:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb5\xf0\x9f\x87\xa6"), ":flag_pa:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb5\xf0\x9f\x87\xaa"), ":flag_pe:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb5\xf0\x9f\x87\xab"), ":flag_pf:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb5\xf0\x9f\x87\xac"), ":flag_pg:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb5\xf0\x9f\x87\xad"), ":flag_ph:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb5\xf0\x9f\x87\xb0"), ":flag_pk:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb5\xf0\x9f\x87\xb1"), ":flag_pl:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb5\xf0\x9f\x87\xb2"), ":flag_pm:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb5\xf0\x9f\x87\xb3"), ":flag_pn:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb5\xf0\x9f\x87\xb7"), ":flag_pr:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb5\xf0\x9f\x87\xb8"), ":flag_ps:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb5\xf0\x9f\x87\xb9"), ":flag_pt:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb5\xf0\x9f\x87\xbc"), ":flag_pw:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb5\xf0\x9f\x87\xbe"), ":flag_py:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb6\xf0\x9f\x87\xa6"), ":flag_qa:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb7\xf0\x9f\x87\xaa"), ":flag_re:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb7\xf0\x9f\x87\xb4"), ":flag_ro:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb7\xf0\x9f\x87\xb8"), ":flag_rs:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb7\xf0\x9f\x87\xba"), ":flag_ru:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb7\xf0\x9f\x87\xbc"), ":flag_rw:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb8\xf0\x9f\x87\xa6"), ":flag_sa:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb8\xf0\x9f\x87\xa7"), ":flag_sb:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb8\xf0\x9f\x87\xa8"), ":flag_sc:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb8\xf0\x9f\x87\xa9"), ":flag_sd:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb8\xf0\x9f\x87\xaa"), ":flag_se:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb8\xf0\x9f\x87\xac"), ":flag_sg:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb8\xf0\x9f\x87\xad"), ":flag_sh:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb8\xf0\x9f\x87\xae"), ":flag_si:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb8\xf0\x9f\x87\xaf"), ":flag_sj:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb8\xf0\x9f\x87\xb0"), ":flag_sk:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb8\xf0\x9f\x87\xb1"), ":flag_sl:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb8\xf0\x9f\x87\xb2"), ":flag_sm:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb8\xf0\x9f\x87\xb3"), ":flag_sn:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb8\xf0\x9f\x87\xb4"), ":flag_so:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb8\xf0\x9f\x87\xb7"), ":flag_sr:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb8\xf0\x9f\x87\xb8"), ":flag_ss:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb8\xf0\x9f\x87\xb9"), ":flag_st:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb8\xf0\x9f\x87\xbb"), ":flag_sv:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb8\xf0\x9f\x87\xbd"), ":flag_sx:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb8\xf0\x9f\x87\xbe"), ":flag_sy:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb8\xf0\x9f\x87\xbf"), ":flag_sz:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb9\xf0\x9f\x87\xa6"), ":flag_ta:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb9\xf0\x9f\x87\xa8"), ":flag_tc:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb9\xf0\x9f\x87\xa9"), ":flag_td:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb9\xf0\x9f\x87\xab"), ":flag_tf:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb9\xf0\x9f\x87\xac"), ":flag_tg:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb9\xf0\x9f\x87\xad"), ":flag_th:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb9\xf0\x9f\x87\xaf"), ":flag_tj:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb9\xf0\x9f\x87\xb0"), ":flag_tk:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb9\xf0\x9f\x87\xb1"), ":flag_tl:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb9\xf0\x9f\x87\xb2"), ":flag_tm:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb9\xf0\x9f\x87\xb3"), ":flag_tn:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb9\xf0\x9f\x87\xb4"), ":flag_to:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb9\xf0\x9f\x87\xb7"), ":flag_tr:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb9\xf0\x9f\x87\xb9"), ":flag_tt:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb9\xf0\x9f\x87\xbb"), ":flag_tv:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb9\xf0\x9f\x87\xbc"), ":flag_tw:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xb9\xf0\x9f\x87\xbf"), ":flag_tz:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xba\xf0\x9f\x87\xa6"), ":flag_ua:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xba\xf0\x9f\x87\xac"), ":flag_ug:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xba\xf0\x9f\x87\xb2"), ":flag_um:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xba\xf0\x9f\x87\xb8"), ":flag_us:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xba\xf0\x9f\x87\xbe"), ":flag_uy:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xba\xf0\x9f\x87\xbf"), ":flag_uz:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xbb\xf0\x9f\x87\xa6"), ":flag_va:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xbb\xf0\x9f\x87\xa8"), ":flag_vc:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xbb\xf0\x9f\x87\xaa"), ":flag_ve:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xbb\xf0\x9f\x87\xac"), ":flag_vg:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xbb\xf0\x9f\x87\xae"), ":flag_vi:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xbb\xf0\x9f\x87\xb3"), ":flag_vn:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xbb\xf0\x9f\x87\xba"), ":flag_vu:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xbc\xf0\x9f\x87\xab"), ":flag_wf:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xbc\xf0\x9f\x87\xb8"), ":flag_ws:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xbd\xf0\x9f\x87\xb0"), ":flag_xk:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xbe\xf0\x9f\x87\xaa"), ":flag_ye:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xbe\xf0\x9f\x87\xb9"), ":flag_yt:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xbf\xf0\x9f\x87\xa6"), ":flag_za:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xbf\xf0\x9f\x87\xb2"), ":flag_zm:" }),
+ QVariant::fromValue(Emoji { QString::fromUtf8("\xf0\x9f\x87\xbf\xf0\x9f\x87\xbc"), ":flag_zw:" }),
+};
+}
diff --git a/src/gui/emojimodel.h b/src/gui/emojimodel.h
new file mode 100644
index 000000000..2d35305d4
--- /dev/null
+++ b/src/gui/emojimodel.h
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) by Felix Weilbach <felix.weilbach@nextcloud.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#pragma once
+
+#include <QObject>
+#include <QSettings>
+#include <QObject>
+#include <QQmlEngine>
+#include <QVariant>
+#include <QVector>
+#include <QAbstractItemModel>
+
+namespace OCC {
+
+struct Emoji
+{
+ Emoji(QString u, QString s, bool isCustom = false)
+ : unicode(std::move(std::move(u)))
+ , shortname(std::move(std::move(s)))
+ , isCustom(isCustom)
+ {
+ }
+ Emoji() = default;
+
+ friend QDataStream &operator<<(QDataStream &arch, const Emoji &object)
+ {
+ arch << object.unicode;
+ arch << object.shortname;
+ return arch;
+ }
+
+ friend QDataStream &operator>>(QDataStream &arch, Emoji &object)
+ {
+ arch >> object.unicode;
+ arch >> object.shortname;
+ object.isCustom = object.unicode.startsWith("image://");
+ return arch;
+ }
+
+ QString unicode;
+ QString shortname;
+ bool isCustom = false;
+
+ Q_GADGET
+ Q_PROPERTY(QString unicode MEMBER unicode)
+ Q_PROPERTY(QString shortname MEMBER shortname)
+ Q_PROPERTY(bool isCustom MEMBER isCustom)
+};
+
+class EmojiCategoriesModel : public QAbstractListModel
+{
+public:
+ QVariant data(const QModelIndex &index, int role) const override;
+ int rowCount(const QModelIndex &parent = QModelIndex()) const override;
+ QHash<int, QByteArray> roleNames() const override;
+
+private:
+ enum Roles {
+ EmojiRole = 0,
+ LabelRole
+ };
+
+ struct Category
+ {
+ QString emoji;
+ QString label;
+ };
+
+ static const std::vector<Category> categories;
+};
+
+class EmojiModel : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QVariantList model READ model NOTIFY modelChanged)
+ Q_PROPERTY(QAbstractListModel *emojiCategoriesModel READ emojiCategoriesModel CONSTANT)
+
+ Q_PROPERTY(QVariantList history READ history NOTIFY historyChanged)
+
+ Q_PROPERTY(QVariantList people MEMBER people CONSTANT)
+ Q_PROPERTY(QVariantList nature MEMBER nature CONSTANT)
+ Q_PROPERTY(QVariantList food MEMBER food CONSTANT)
+ Q_PROPERTY(QVariantList activity MEMBER activity CONSTANT)
+ Q_PROPERTY(QVariantList travel MEMBER travel CONSTANT)
+ Q_PROPERTY(QVariantList objects MEMBER objects CONSTANT)
+ Q_PROPERTY(QVariantList symbols MEMBER symbols CONSTANT)
+ Q_PROPERTY(QVariantList flags MEMBER flags CONSTANT)
+
+public:
+ explicit EmojiModel(QObject *parent = nullptr)
+ : QObject(parent)
+ {
+ }
+
+ Q_INVOKABLE QVariantList history() const;
+ Q_INVOKABLE void setCategory(const QString &category);
+ Q_INVOKABLE void emojiUsed(const QVariant &modelData);
+
+ QVariantList model() const;
+ QAbstractListModel *emojiCategoriesModel();
+
+signals:
+ void historyChanged();
+ void modelChanged();
+
+private:
+ static const QVariantList people;
+ static const QVariantList nature;
+ static const QVariantList food;
+ static const QVariantList activity;
+ static const QVariantList travel;
+ static const QVariantList objects;
+ static const QVariantList symbols;
+ static const QVariantList flags;
+
+ QSettings _settings;
+ QString _category = "history";
+
+ EmojiCategoriesModel _emojiCategoriesModel;
+};
+
+}
+
+Q_DECLARE_METATYPE(OCC::Emoji)
diff --git a/src/gui/main.cpp b/src/gui/main.cpp
index a7a47e16e..ec4a347eb 100644
--- a/src/gui/main.cpp
+++ b/src/gui/main.cpp
@@ -16,6 +16,7 @@
#include <cmath>
#include <csignal>
+#include <qqml.h>
#ifdef Q_OS_UNIX
#include <sys/time.h>
@@ -26,6 +27,8 @@
#include "theme.h"
#include "common/utility.h"
#include "cocoainitializer.h"
+#include "userstatusselectormodel.h"
+#include "emojimodel.h"
#if defined(BUILD_UPDATER)
#include "updater/updater.h"
@@ -54,6 +57,15 @@ int main(int argc, char **argv)
Q_INIT_RESOURCE(resources);
Q_INIT_RESOURCE(theme);
+ qmlRegisterType<EmojiModel>("com.nextcloud.desktopclient", 1, 0, "EmojiModel");
+ qRegisterMetaTypeStreamOperators<Emoji>();
+ qmlRegisterType<UserStatusSelectorModel>("com.nextcloud.desktopclient", 1, 0,
+ "UserStatusSelectorModel");
+ qmlRegisterUncreatableType<OCC::UserStatus>("com.nextcloud.desktopclient", 1, 0, "UserStatus",
+ "Access to Status enum");
+ qRegisterMetaType<OCC::UserStatus>("UserStatus");
+
+
// Work around a bug in KDE's qqc2-desktop-style which breaks
// buttons with icons not based on a name, by forcing a style name
// the platformtheme plugin won't try to force qqc2-desktops-style
diff --git a/src/gui/socketapi/socketapi.cpp b/src/gui/socketapi/socketapi.cpp
index 0669ebc64..0b3d37582 100644
--- a/src/gui/socketapi/socketapi.cpp
+++ b/src/gui/socketapi/socketapi.cpp
@@ -617,7 +617,7 @@ void SocketApi::command_EDIT(const QString &localFile, SocketListener *listener)
params.addQueryItem("path", fileData.serverRelativePath);
params.addQueryItem("editorId", editor->id());
job->addQueryParams(params);
- job->usePOST();
+ job->setVerb(JsonApiJob::Verb::Post);
QObject::connect(job, &JsonApiJob::jsonReceived, [](const QJsonDocument &json){
auto data = json.object().value("ocs").toObject().value("data").toObject();
diff --git a/src/gui/tray/UserLine.qml b/src/gui/tray/UserLine.qml
index 4143acaee..c418e3c1f 100644
--- a/src/gui/tray/UserLine.qml
+++ b/src/gui/tray/UserLine.qml
@@ -14,6 +14,11 @@ MenuItem {
Accessible.role: Accessible.MenuItem
Accessible.name: qsTr("Account entry")
+ property variant dialog;
+ property variant comp;
+
+ signal showUserStatusSelectorDialog(int id)
+
RowLayout {
id: userLineLayout
spacing: 0
@@ -189,6 +194,29 @@ MenuItem {
}
MenuItem {
+ visible: model.isConnected && model.serverHasUserStatus
+ height: visible ? implicitHeight : 0
+
+ text: qsTr("Set status")
+ font.pixelSize: Style.topLinePixelSize
+ hoverEnabled: true
+ onClicked: {
+ showUserStatusSelectorDialog(index)
+ accountMenu.close()
+ }
+
+ background: Item {
+ height: parent.height
+ width: parent.menu.width
+ Rectangle {
+ anchors.fill: parent
+ anchors.margins: 1
+ color: parent.parent.hovered ? Style.lightHover : "transparent"
+ }
+ }
+ }
+
+ MenuItem {
text: model.isConnected ? qsTr("Log out") : qsTr("Log in")
font.pixelSize: Style.topLinePixelSize
hoverEnabled: true
diff --git a/src/gui/tray/UserModel.cpp b/src/gui/tray/UserModel.cpp
index 907392571..56a387aa5 100644
--- a/src/gui/tray/UserModel.cpp
+++ b/src/gui/tray/UserModel.cpp
@@ -4,6 +4,7 @@
#include "accountmanager.h"
#include "owncloudgui.h"
#include <pushnotifications.h>
+#include "userstatusselectormodel.h"
#include "syncengine.h"
#include "ocsjob.h"
#include "configfile.h"
@@ -11,7 +12,9 @@
#include "logger.h"
#include "guiutility.h"
#include "syncfileitem.h"
+#include "tray/ActivityListModel.h"
#include "tray/NotificationCache.h"
+#include "userstatusconnector.h"
#include <QDesktopServices>
#include <QIcon>
@@ -25,8 +28,8 @@
#define NOTIFICATION_REQUEST_FREE_PERIOD 15000
namespace {
- constexpr qint64 expiredActivitiesCheckIntervalMsecs = 1000 * 60;
- constexpr qint64 activityDefaultExpirationTimeMsecs = 1000 * 60 * 10;
+constexpr qint64 expiredActivitiesCheckIntervalMsecs = 1000 * 60;
+constexpr qint64 activityDefaultExpirationTimeMsecs = 1000 * 60 * 10;
}
namespace OCC {
@@ -65,7 +68,7 @@ User::User(AccountStatePtr &account, const bool &isCurrent, QObject *parent)
connect(this, &User::guiLog, Logger::instance(), &Logger::guiLog);
connect(_account->account().data(), &Account::accountChangedAvatar, this, &User::avatarChanged);
- connect(_account.data(), &AccountState::statusChanged, this, &User::statusChanged);
+ connect(_account->account().data(), &Account::userStatusChanged, this, &User::statusChanged);
connect(_account.data(), &AccountState::desktopNotificationsAllowedChanged, this, &User::desktopNotificationsAllowedChanged);
connect(_activityModel, &ActivityListModel::sendNotificationRequest, this, &User::slotSendNotificationRequest);
@@ -236,10 +239,10 @@ void User::slotRefreshActivities()
_activityModel->slotRefreshActivity();
}
-void User::slotRefreshUserStatus()
+void User::slotRefreshUserStatus()
{
if (_account.data() && _account.data()->isConnected()) {
- _account.data()->fetchUserStatus();
+ _account->account()->userStatusConnector()->fetchUserStatus();
}
}
@@ -621,29 +624,29 @@ QString User::server(bool shortened) const
return serverUrl;
}
-UserStatus::Status User::status() const
+UserStatus::OnlineStatus User::status() const
{
- return _account->status();
+ return _account->account()->userStatusConnector()->userStatus().state();
}
QString User::statusMessage() const
{
- return _account->statusMessage();
+ return _account->account()->userStatusConnector()->userStatus().message();
}
QUrl User::statusIcon() const
{
- return _account->statusIcon();
+ return _account->account()->userStatusConnector()->userStatus().stateIcon();
}
QString User::statusEmoji() const
{
- return _account->statusEmoji();
+ return _account->account()->userStatusConnector()->userStatus().icon();
}
bool User::serverHasUserStatus() const
{
- return _account->account()->capabilities().userStatus();
+ return _account->account()->capabilities().userStatusNotification();
}
QImage User::avatar() const
@@ -921,6 +924,15 @@ Q_INVOKABLE void UserModel::removeAccount(const int &id)
endRemoveRows();
}
+std::shared_ptr<OCC::UserStatusConnector> UserModel::userStatusConnector(int id)
+{
+ if (id < 0 || id >= _users.size()) {
+ return nullptr;
+ }
+
+ return _users[id]->account()->userStatusConnector();
+}
+
int UserModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
diff --git a/src/gui/tray/UserModel.h b/src/gui/tray/UserModel.h
index b45fde7c3..c11b2c476 100644
--- a/src/gui/tray/UserModel.h
+++ b/src/gui/tray/UserModel.h
@@ -12,6 +12,8 @@
#include "accountmanager.h"
#include "folderman.h"
#include "NotificationCache.h"
+#include "userstatusselectormodel.h"
+#include "userstatusconnector.h"
#include <chrono>
namespace OCC {
@@ -55,7 +57,7 @@ public:
void removeAccount() const;
QString avatarUrl() const;
bool isDesktopNotificationsAllowed() const;
- UserStatus::Status status() const;
+ UserStatus::OnlineStatus status() const;
QString statusMessage() const;
QUrl statusIcon() const;
QString statusEmoji() const;
@@ -158,6 +160,8 @@ public:
Q_INVOKABLE void logout(const int &id);
Q_INVOKABLE void removeAccount(const int &id);
+ Q_INVOKABLE std::shared_ptr<OCC::UserStatusConnector> userStatusConnector(int id);
+
ActivityListModel *currentActivityModel();
enum UserRoles {
diff --git a/src/gui/tray/Window.qml b/src/gui/tray/Window.qml
index ccb4af74e..31d5143de 100644
--- a/src/gui/tray/Window.qml
+++ b/src/gui/tray/Window.qml
@@ -140,6 +140,10 @@ Window {
}
}
+ Loader {
+ id: userStatusSelectorDialogLoader
+ }
+
Menu {
id: accountMenu
@@ -167,7 +171,14 @@ Window {
Instantiator {
id: userLineInstantiator
model: UserModel
- delegate: UserLine {}
+ delegate: UserLine {
+ onShowUserStatusSelectorDialog: {
+ userStatusSelectorDialogLoader.source = "qrc:/qml/src/gui/UserStatusSelectorDialog.qml"
+ userStatusSelectorDialogLoader.item.title = qsTr("Set user status")
+ userStatusSelectorDialogLoader.item.model.load(index)
+ userStatusSelectorDialogLoader.item.show()
+ }
+ }
onObjectAdded: accountMenu.insertItem(index, object)
onObjectRemoved: accountMenu.removeItem(object)
}
diff --git a/src/gui/userstatus.cpp b/src/gui/userstatus.cpp
deleted file mode 100644
index 55d929eee..000000000
--- a/src/gui/userstatus.cpp
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright (C) by Camila <hello@camila.codes>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-#include "userstatus.h"
-#include "account.h"
-#include "accountstate.h"
-#include "networkjobs.h"
-#include "folderman.h"
-#include "creds/abstractcredentials.h"
-#include "theme.h"
-#include "capabilities.h"
-
-#include <QTimer>
-#include <QJsonDocument>
-#include <QJsonObject>
-
-namespace OCC {
-
-Q_LOGGING_CATEGORY(lcUserStatus, "nextcloud.gui.userstatus", QtInfoMsg)
-
-namespace {
- UserStatus::Status stringToEnum(const QString &status)
- {
- // it needs to match the Status enum
- const QHash<QString, UserStatus::Status> preDefinedStatus{
- {"online", UserStatus::Status::Online},
- {"dnd", UserStatus::Status::DoNotDisturb},
- {"away", UserStatus::Status::Away},
- {"offline", UserStatus::Status::Offline},
- {"invisible", UserStatus::Status::Invisible}
- };
-
- // api should return invisible, dnd,... toLower() it is to make sure
- // it matches _preDefinedStatus, otherwise the default is online (0)
- return preDefinedStatus.value(status.toLower(), UserStatus::Status::Online);
- }
-}
-
-UserStatus::UserStatus(QObject *parent)
- : QObject(parent)
-{
-}
-
-void UserStatus::fetchUserStatus(AccountPtr account)
-{
- if (!account->capabilities().userStatus()) {
- return;
- }
-
- if (_job) {
- _job->deleteLater();
- }
-
- _job = new JsonApiJob(account, QStringLiteral("/ocs/v2.php/apps/user_status/api/v1/user_status"), this);
- connect(_job.data(), &JsonApiJob::jsonReceived, this, &UserStatus::slotFetchUserStatusFinished);
- _job->start();
-}
-
-void UserStatus::slotFetchUserStatusFinished(const QJsonDocument &json, int statusCode)
-{
- const QJsonObject defaultValues {
- {"icon", ""},
- {"message", ""},
- {"status", "online"},
- {"messageIsPredefined", "false"},
- {"statusIsUserDefined", "false"}
- };
-
- if (statusCode != 200) {
- qCInfo(lcUserStatus) << "Slot fetch UserStatus finished with status code" << statusCode;
- qCInfo(lcUserStatus) << "Using then default values as if user has not set any status" << defaultValues;
- }
-
- const auto retrievedData = json.object().value("ocs").toObject().value("data").toObject(defaultValues);
-
- _emoji = retrievedData.value("icon").toString().trimmed();
- _status = stringToEnum(retrievedData.value("status").toString());
- _message = retrievedData.value("message").toString().trimmed();
-
- emit fetchUserStatusFinished();
-}
-
-UserStatus::Status UserStatus::status() const
-{
- return _status;
-}
-
-QString UserStatus::message() const
-{
- return _message;
-}
-
-QString UserStatus::emoji() const
-{
- return _emoji;
-}
-
-QUrl UserStatus::icon() const
-{
- switch (_status) {
- case Status::Away:
- return Theme::instance()->statusAwayImageSource();
- case Status::DoNotDisturb:
- return Theme::instance()->statusDoNotDisturbImageSource();
- case Status::Invisible:
- case Status::Offline:
- return Theme::instance()->statusInvisibleImageSource();
- case Status::Online:
- return Theme::instance()->statusOnlineImageSource();
- }
-
- Q_UNREACHABLE();
-}
-
-} // namespace OCC
diff --git a/src/gui/userstatus.h b/src/gui/userstatus.h
deleted file mode 100644
index 3e952a50b..000000000
--- a/src/gui/userstatus.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) by Camila <hello@camila.codes>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-#ifndef USERSTATUS_H
-#define USERSTATUS_H
-
-#include <QPointer>
-#include "accountfwd.h"
-
-namespace OCC {
-
-class JsonApiJob;
-
-class UserStatus : public QObject
-{
- Q_OBJECT
-
-public:
- explicit UserStatus(QObject *parent = nullptr);
- enum class Status {
- Online,
- DoNotDisturb,
- Away,
- Offline,
- Invisible
- };
- Q_ENUM(Status);
- void fetchUserStatus(AccountPtr account);
- Status status() const;
- QString message() const;
- QString emoji() const;
- QUrl icon() const;
-
-private slots:
- void slotFetchUserStatusFinished(const QJsonDocument &json, int statusCode);
-
-signals:
- void fetchUserStatusFinished();
-
-private:
- QPointer<JsonApiJob> _job; // the currently running job
- Status _status = Status::Online;
- QString _message;
- QString _emoji;
-};
-
-
-} // namespace OCC
-
-#endif //USERSTATUS_H
diff --git a/src/gui/userstatusselectormodel.cpp b/src/gui/userstatusselectormodel.cpp
new file mode 100644
index 000000000..c241474e0
--- /dev/null
+++ b/src/gui/userstatusselectormodel.cpp
@@ -0,0 +1,474 @@
+/*
+ * Copyright (C) by Felix Weilbach <felix.weilbach@nextcloud.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "userstatusselectormodel.h"
+#include "tray/UserModel.h"
+
+#include <ocsuserstatusconnector.h>
+#include <qnamespace.h>
+#include <userstatusconnector.h>
+#include <theme.h>
+
+#include <QDateTime>
+#include <QLoggingCategory>
+
+#include <algorithm>
+#include <cmath>
+#include <cstddef>
+
+namespace OCC {
+
+Q_LOGGING_CATEGORY(lcUserStatusDialogModel, "nextcloud.gui.userstatusdialogmodel", QtInfoMsg)
+
+UserStatusSelectorModel::UserStatusSelectorModel(QObject *parent)
+ : QObject(parent)
+ , _dateTimeProvider(new DateTimeProvider)
+{
+ _userStatus.setIcon("😀");
+}
+
+UserStatusSelectorModel::UserStatusSelectorModel(std::shared_ptr<UserStatusConnector> userStatusConnector, QObject *parent)
+ : QObject(parent)
+ , _userStatusConnector(userStatusConnector)
+ , _userStatus("no-id", "", "😀", UserStatus::OnlineStatus::Online, false, {})
+ , _dateTimeProvider(new DateTimeProvider)
+{
+ _userStatus.setIcon("😀");
+ init();
+}
+
+UserStatusSelectorModel::UserStatusSelectorModel(std::shared_ptr<UserStatusConnector> userStatusConnector,
+ std::unique_ptr<DateTimeProvider> dateTimeProvider,
+ QObject *parent)
+ : QObject(parent)
+ , _userStatusConnector(userStatusConnector)
+ , _dateTimeProvider(std::move(dateTimeProvider))
+{
+ _userStatus.setIcon("😀");
+ init();
+}
+
+UserStatusSelectorModel::UserStatusSelectorModel(const UserStatus &userStatus,
+ std::unique_ptr<DateTimeProvider> dateTimeProvider, QObject *parent)
+ : QObject(parent)
+ , _userStatus(userStatus)
+ , _dateTimeProvider(std::move(dateTimeProvider))
+{
+ _userStatus.setIcon("😀");
+}
+
+UserStatusSelectorModel::UserStatusSelectorModel(const UserStatus &userStatus,
+ QObject *parent)
+ : QObject(parent)
+ , _userStatus(userStatus)
+{
+ _userStatus.setIcon("😀");
+}
+
+void UserStatusSelectorModel::load(int id)
+{
+ reset();
+ _userStatusConnector = UserModel::instance()->userStatusConnector(id);
+ init();
+}
+
+void UserStatusSelectorModel::reset()
+{
+ if (_userStatusConnector) {
+ disconnect(_userStatusConnector.get(), &UserStatusConnector::userStatusFetched, this,
+ &UserStatusSelectorModel::onUserStatusFetched);
+ disconnect(_userStatusConnector.get(), &UserStatusConnector::predefinedStatusesFetched, this,
+ &UserStatusSelectorModel::onPredefinedStatusesFetched);
+ disconnect(_userStatusConnector.get(), &UserStatusConnector::error, this,
+ &UserStatusSelectorModel::onError);
+ disconnect(_userStatusConnector.get(), &UserStatusConnector::userStatusSet, this,
+ &UserStatusSelectorModel::onUserStatusSet);
+ disconnect(_userStatusConnector.get(), &UserStatusConnector::messageCleared, this,
+ &UserStatusSelectorModel::onMessageCleared);
+ }
+ _userStatusConnector = nullptr;
+}
+
+void UserStatusSelectorModel::init()
+{
+ if (!_userStatusConnector) {
+ return;
+ }
+
+ connect(_userStatusConnector.get(), &UserStatusConnector::userStatusFetched, this,
+ &UserStatusSelectorModel::onUserStatusFetched);
+ connect(_userStatusConnector.get(), &UserStatusConnector::predefinedStatusesFetched, this,
+ &UserStatusSelectorModel::onPredefinedStatusesFetched);
+ connect(_userStatusConnector.get(), &UserStatusConnector::error, this,
+ &UserStatusSelectorModel::onError);
+ connect(_userStatusConnector.get(), &UserStatusConnector::userStatusSet, this,
+ &UserStatusSelectorModel::onUserStatusSet);
+ connect(_userStatusConnector.get(), &UserStatusConnector::messageCleared, this,
+ &UserStatusSelectorModel::onMessageCleared);
+
+ _userStatusConnector->fetchUserStatus();
+ _userStatusConnector->fetchPredefinedStatuses();
+}
+
+UserStatusSelectorModel::~UserStatusSelectorModel()
+{
+ qCDebug(lcUserStatusDialogModel) << "Destroyed";
+}
+
+void UserStatusSelectorModel::onUserStatusSet()
+{
+ qCDebug(lcUserStatusDialogModel) << "Emit finished";
+ emit finished();
+}
+
+void UserStatusSelectorModel::onMessageCleared()
+{
+ emit finished();
+}
+
+void UserStatusSelectorModel::onError(UserStatusConnector::Error error)
+{
+ qCWarning(lcUserStatusDialogModel) << "Error:" << error;
+
+ switch (error) {
+ case UserStatusConnector::Error::CouldNotFetchPredefinedUserStatuses:
+ setError(tr("Could not fetch predefined statuses. Make sure you are connected to the server."));
+ return;
+
+ case UserStatusConnector::Error::CouldNotFetchUserStatus:
+ setError(tr("Could not fetch user status. Make sure you are connected to the server."));
+ return;
+
+ case UserStatusConnector::Error::UserStatusNotSupported:
+ setError(tr("User status feature is not supported. You will not be able to set your user status."));
+ return;
+
+ case UserStatusConnector::Error::EmojisNotSupported:
+ setError(tr("Emojis feature is not supported. Some user status functionality may not work."));
+ return;
+
+ case UserStatusConnector::Error::CouldNotSetUserStatus:
+ setError(tr("Could not set user status. Make sure you are connected to the server."));
+ return;
+
+ case UserStatusConnector::Error::CouldNotClearMessage:
+ setError(tr("Could not clear user status message. Make sure you are connected to the server."));
+ return;
+ }
+
+ Q_UNREACHABLE();
+}
+
+void UserStatusSelectorModel::setError(const QString &reason)
+{
+ _errorMessage = reason;
+ emit errorMessageChanged();
+}
+
+void UserStatusSelectorModel::clearError()
+{
+ setError("");
+}
+
+void UserStatusSelectorModel::setOnlineStatus(UserStatus::OnlineStatus status)
+{
+ if (status == _userStatus.state()) {
+ return;
+ }
+
+ _userStatus.setState(status);
+ emit onlineStatusChanged();
+}
+
+QUrl UserStatusSelectorModel::onlineIcon() const
+{
+ return Theme::instance()->statusOnlineImageSource();
+}
+
+QUrl UserStatusSelectorModel::awayIcon() const
+{
+ return Theme::instance()->statusAwayImageSource();
+}
+QUrl UserStatusSelectorModel::dndIcon() const
+{
+ return Theme::instance()->statusDoNotDisturbImageSource();
+}
+QUrl UserStatusSelectorModel::invisibleIcon() const
+{
+ return Theme::instance()->statusInvisibleImageSource();
+}
+
+UserStatus::OnlineStatus UserStatusSelectorModel::onlineStatus() const
+{
+ return _userStatus.state();
+}
+
+QString UserStatusSelectorModel::userStatusMessage() const
+{
+ return _userStatus.message();
+}
+
+void UserStatusSelectorModel::setUserStatusMessage(const QString &message)
+{
+ _userStatus.setMessage(message);
+ _userStatus.setMessagePredefined(false);
+ emit userStatusChanged();
+}
+
+void UserStatusSelectorModel::setUserStatusEmoji(const QString &emoji)
+{
+ _userStatus.setIcon(emoji);
+ _userStatus.setMessagePredefined(false);
+ emit userStatusChanged();
+}
+
+QString UserStatusSelectorModel::userStatusEmoji() const
+{
+ return _userStatus.icon();
+}
+
+void UserStatusSelectorModel::onUserStatusFetched(const UserStatus &userStatus)
+{
+ if (userStatus.state() != UserStatus::OnlineStatus::Offline) {
+ _userStatus.setState(userStatus.state());
+ }
+ _userStatus.setMessage(userStatus.message());
+ _userStatus.setMessagePredefined(userStatus.messagePredefined());
+ _userStatus.setId(userStatus.id());
+ _userStatus.setClearAt(userStatus.clearAt());
+
+ if (!userStatus.icon().isEmpty()) {
+ _userStatus.setIcon(userStatus.icon());
+ }
+
+ emit userStatusChanged();
+ emit onlineStatusChanged();
+ emit clearAtChanged();
+}
+
+Optional<ClearAt> UserStatusSelectorModel::clearStageTypeToDateTime(ClearStageType type) const
+{
+ switch (type) {
+ case ClearStageType::DontClear:
+ return {};
+
+ case ClearStageType::HalfHour: {
+ ClearAt clearAt;
+ clearAt._type = ClearAtType::Period;
+ clearAt._period = 60 * 30;
+ return clearAt;
+ }
+
+ case ClearStageType::OneHour: {
+ ClearAt clearAt;
+ clearAt._type = ClearAtType::Period;
+ clearAt._period = 60 * 60;
+ return clearAt;
+ }
+
+ case ClearStageType::FourHour: {
+ ClearAt clearAt;
+ clearAt._type = ClearAtType::Period;
+ clearAt._period = 60 * 60 * 4;
+ return clearAt;
+ }
+
+ case ClearStageType::Today: {
+ ClearAt clearAt;
+ clearAt._type = ClearAtType::EndOf;
+ clearAt._endof = "day";
+ return clearAt;
+ }
+
+ case ClearStageType::Week: {
+ ClearAt clearAt;
+ clearAt._type = ClearAtType::EndOf;
+ clearAt._endof = "week";
+ return clearAt;
+ }
+
+ default:
+ Q_UNREACHABLE();
+ }
+}
+
+void UserStatusSelectorModel::setUserStatus()
+{
+ Q_ASSERT(_userStatusConnector);
+ if (!_userStatusConnector) {
+ return;
+ }
+
+ clearError();
+ _userStatusConnector->setUserStatus(_userStatus);
+}
+
+void UserStatusSelectorModel::clearUserStatus()
+{
+ Q_ASSERT(_userStatusConnector);
+ if (!_userStatusConnector) {
+ return;
+ }
+
+ clearError();
+ _userStatusConnector->clearMessage();
+}
+
+void UserStatusSelectorModel::onPredefinedStatusesFetched(const std::vector<UserStatus> &statuses)
+{
+ _predefinedStatuses = statuses;
+ emit predefinedStatusesChanged();
+}
+
+UserStatus UserStatusSelectorModel::predefinedStatus(int index) const
+{
+ Q_ASSERT(0 <= index && index < static_cast<int>(_predefinedStatuses.size()));
+ return _predefinedStatuses[index];
+}
+
+int UserStatusSelectorModel::predefinedStatusesCount() const
+{
+ return static_cast<int>(_predefinedStatuses.size());
+}
+
+void UserStatusSelectorModel::setPredefinedStatus(int index)
+{
+ Q_ASSERT(0 <= index && index < static_cast<int>(_predefinedStatuses.size()));
+
+ _userStatus.setMessagePredefined(true);
+ const auto predefinedStatus = _predefinedStatuses[index];
+ _userStatus.setId(predefinedStatus.id());
+ _userStatus.setMessage(predefinedStatus.message());
+ _userStatus.setIcon(predefinedStatus.icon());
+ _userStatus.setClearAt(predefinedStatus.clearAt());
+
+ emit userStatusChanged();
+ emit clearAtChanged();
+}
+
+QString UserStatusSelectorModel::clearAtStageToString(ClearStageType stage) const
+{
+ switch (stage) {
+ case ClearStageType::DontClear:
+ return tr("Don't clear");
+
+ case ClearStageType::HalfHour:
+ return tr("30 minutes");
+
+ case ClearStageType::OneHour:
+ return tr("1 hour");
+
+ case ClearStageType::FourHour:
+ return tr("4 hours");
+
+ case ClearStageType::Today:
+ return tr("Today");
+
+ case ClearStageType::Week:
+ return tr("This week");
+
+ default:
+ Q_UNREACHABLE();
+ }
+}
+
+QStringList UserStatusSelectorModel::clearAtValues() const
+{
+ QStringList clearAtStages;
+ std::transform(_clearStages.begin(), _clearStages.end(),
+ std::back_inserter(clearAtStages),
+ [this](const ClearStageType &stage) { return clearAtStageToString(stage); });
+
+ return clearAtStages;
+}
+
+void UserStatusSelectorModel::setClearAt(int index)
+{
+ Q_ASSERT(0 <= index && index < static_cast<int>(_clearStages.size()));
+ _userStatus.setClearAt(clearStageTypeToDateTime(_clearStages[index]));
+ emit clearAtChanged();
+}
+
+QString UserStatusSelectorModel::errorMessage() const
+{
+ return _errorMessage;
+}
+
+QString UserStatusSelectorModel::timeDifferenceToString(int differenceSecs) const
+{
+ if (differenceSecs < 60) {
+ return tr("Less than a minute");
+ } else if (differenceSecs < 60 * 60) {
+ const auto minutesLeft = std::ceil(differenceSecs / 60.0);
+ if (minutesLeft == 1) {
+ return tr("1 minute");
+ } else {
+ return tr("%1 minutes").arg(minutesLeft);
+ }
+ } else if (differenceSecs < 60 * 60 * 24) {
+ const auto hoursLeft = std::ceil(differenceSecs / 60.0 / 60.0);
+ if (hoursLeft == 1) {
+ return tr("1 hour");
+ } else {
+ return tr("%1 hours").arg(hoursLeft);
+ }
+ } else {
+ const auto daysLeft = std::ceil(differenceSecs / 60.0 / 60.0 / 24.0);
+ if (daysLeft == 1) {
+ return tr("1 day");
+ } else {
+ return tr("%1 days").arg(daysLeft);
+ }
+ }
+}
+
+QString UserStatusSelectorModel::clearAtReadable(const Optional<ClearAt> &clearAt) const
+{
+ if (clearAt) {
+ switch (clearAt->_type) {
+ case ClearAtType::Period: {
+ return timeDifferenceToString(clearAt->_period);
+ }
+
+ case ClearAtType::Timestamp: {
+ const int difference = static_cast<int>(clearAt->_timestamp - _dateTimeProvider->currentDateTime().toTime_t());
+ return timeDifferenceToString(difference);
+ }
+
+ case ClearAtType::EndOf: {
+ if (clearAt->_endof == "day") {
+ return tr("Today");
+ } else if (clearAt->_endof == "week") {
+ return tr("This week");
+ }
+ Q_UNREACHABLE();
+ }
+
+ default:
+ Q_UNREACHABLE();
+ }
+ }
+ return tr("Don't clear");
+}
+
+QString UserStatusSelectorModel::predefinedStatusClearAt(int index) const
+{
+ return clearAtReadable(predefinedStatus(index).clearAt());
+}
+
+QString UserStatusSelectorModel::clearAt() const
+{
+ return clearAtReadable(_userStatus.clearAt());
+}
+}
diff --git a/src/gui/userstatusselectormodel.h b/src/gui/userstatusselectormodel.h
new file mode 100644
index 000000000..cc90b777d
--- /dev/null
+++ b/src/gui/userstatusselectormodel.h
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) by Felix Weilbach <felix.weilbach@nextcloud.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#pragma once
+
+#include "common/result.h"
+
+#include <userstatusconnector.h>
+#include <datetimeprovider.h>
+
+#include <QObject>
+#include <QMetaType>
+#include <QtNumeric>
+
+#include <cstddef>
+#include <memory>
+#include <vector>
+
+namespace OCC {
+
+class UserStatusSelectorModel : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QString userStatusMessage READ userStatusMessage NOTIFY userStatusChanged)
+ Q_PROPERTY(QString userStatusEmoji READ userStatusEmoji WRITE setUserStatusEmoji NOTIFY userStatusChanged)
+ Q_PROPERTY(OCC::UserStatus::OnlineStatus onlineStatus READ onlineStatus WRITE setOnlineStatus NOTIFY onlineStatusChanged)
+ Q_PROPERTY(int predefinedStatusesCount READ predefinedStatusesCount NOTIFY predefinedStatusesChanged)
+ Q_PROPERTY(QStringList clearAtValues READ clearAtValues CONSTANT)
+ Q_PROPERTY(QString clearAt READ clearAt NOTIFY clearAtChanged)
+ Q_PROPERTY(QString errorMessage READ errorMessage NOTIFY errorMessageChanged)
+ Q_PROPERTY(QUrl onlineIcon READ onlineIcon CONSTANT)
+ Q_PROPERTY(QUrl awayIcon READ awayIcon CONSTANT)
+ Q_PROPERTY(QUrl dndIcon READ dndIcon CONSTANT)
+ Q_PROPERTY(QUrl invisibleIcon READ invisibleIcon CONSTANT)
+
+public:
+ explicit UserStatusSelectorModel(QObject *parent = nullptr);
+
+ explicit UserStatusSelectorModel(std::shared_ptr<UserStatusConnector> userStatusConnector,
+ QObject *parent = nullptr);
+
+ explicit UserStatusSelectorModel(std::shared_ptr<UserStatusConnector> userStatusConnector,
+ std::unique_ptr<DateTimeProvider> dateTimeProvider,
+ QObject *parent = nullptr);
+
+ explicit UserStatusSelectorModel(const UserStatus &userStatus,
+ std::unique_ptr<DateTimeProvider> dateTimeProvider,
+ QObject *parent = nullptr);
+
+ explicit UserStatusSelectorModel(const UserStatus &userStatus,
+ QObject *parent = nullptr);
+
+ ~UserStatusSelectorModel() override;
+
+ Q_INVOKABLE void load(int id);
+
+ Q_REQUIRED_RESULT UserStatus::OnlineStatus onlineStatus() const;
+ Q_INVOKABLE void setOnlineStatus(OCC::UserStatus::OnlineStatus status);
+
+ Q_REQUIRED_RESULT QUrl onlineIcon() const;
+ Q_REQUIRED_RESULT QUrl awayIcon() const;
+ Q_REQUIRED_RESULT QUrl dndIcon() const;
+ Q_REQUIRED_RESULT QUrl invisibleIcon() const;
+
+ Q_REQUIRED_RESULT QString userStatusMessage() const;
+ Q_INVOKABLE void setUserStatusMessage(const QString &message);
+ void setUserStatusEmoji(const QString &emoji);
+ Q_REQUIRED_RESULT QString userStatusEmoji() const;
+
+ Q_INVOKABLE void setUserStatus();
+ Q_INVOKABLE void clearUserStatus();
+
+ Q_REQUIRED_RESULT int predefinedStatusesCount() const;
+ Q_INVOKABLE UserStatus predefinedStatus(int index) const;
+ Q_INVOKABLE QString predefinedStatusClearAt(int index) const;
+ Q_INVOKABLE void setPredefinedStatus(int index);
+
+ Q_REQUIRED_RESULT QStringList clearAtValues() const;
+ Q_REQUIRED_RESULT QString clearAt() const;
+ Q_INVOKABLE void setClearAt(int index);
+
+ Q_REQUIRED_RESULT QString errorMessage() const;
+
+signals:
+ void errorMessageChanged();
+ void userStatusChanged();
+ void onlineStatusChanged();
+ void clearAtChanged();
+ void predefinedStatusesChanged();
+ void finished();
+
+private:
+ enum class ClearStageType {
+ DontClear,
+ HalfHour,
+ OneHour,
+ FourHour,
+ Today,
+ Week
+ };
+
+ void init();
+ void reset();
+ void onUserStatusFetched(const UserStatus &userStatus);
+ void onPredefinedStatusesFetched(const std::vector<UserStatus> &statuses);
+ void onUserStatusSet();
+ void onMessageCleared();
+ void onError(UserStatusConnector::Error error);
+
+ Q_REQUIRED_RESULT QString clearAtStageToString(ClearStageType stage) const;
+ Q_REQUIRED_RESULT QString clearAtReadable(const Optional<ClearAt> &clearAt) const;
+ Q_REQUIRED_RESULT QString timeDifferenceToString(int differenceSecs) const;
+ Q_REQUIRED_RESULT Optional<ClearAt> clearStageTypeToDateTime(ClearStageType type) const;
+ void setError(const QString &reason);
+ void clearError();
+
+ std::shared_ptr<UserStatusConnector> _userStatusConnector {};
+ std::vector<UserStatus> _predefinedStatuses;
+ UserStatus _userStatus;
+ std::unique_ptr<DateTimeProvider> _dateTimeProvider;
+
+ QString _errorMessage;
+
+ std::vector<ClearStageType> _clearStages = {
+ ClearStageType::DontClear,
+ ClearStageType::HalfHour,
+ ClearStageType::OneHour,
+ ClearStageType::FourHour,
+ ClearStageType::Today,
+ ClearStageType::Week
+ };
+};
+}
diff --git a/src/libsync/CMakeLists.txt b/src/libsync/CMakeLists.txt
index 3c38c6374..750d45ec8 100644
--- a/src/libsync/CMakeLists.txt
+++ b/src/libsync/CMakeLists.txt
@@ -55,6 +55,9 @@ set(libsync_SRCS
theme.cpp
clientsideencryption.cpp
clientsideencryptionjobs.cpp
+ datetimeprovider.cpp
+ ocsuserstatusconnector.cpp
+ userstatusconnector.cpp
creds/dummycredentials.cpp
creds/abstractcredentials.cpp
creds/credentialscommon.cpp
diff --git a/src/libsync/abstractnetworkjob.cpp b/src/libsync/abstractnetworkjob.cpp
index be9c01c93..6bb00a6b2 100644
--- a/src/libsync/abstractnetworkjob.cpp
+++ b/src/libsync/abstractnetworkjob.cpp
@@ -139,6 +139,15 @@ QNetworkReply *AbstractNetworkJob::sendRequest(const QByteArray &verb, const QUr
return reply;
}
+QNetworkReply *AbstractNetworkJob::sendRequest(const QByteArray &verb, const QUrl &url,
+ QNetworkRequest req, const QByteArray &requestBody)
+{
+ auto reply = _account->sendRawRequest(verb, url, req, requestBody);
+ _requestBody = nullptr;
+ adoptRequest(reply);
+ return reply;
+}
+
void AbstractNetworkJob::adoptRequest(QNetworkReply *reply)
{
addTimer(reply);
diff --git a/src/libsync/abstractnetworkjob.h b/src/libsync/abstractnetworkjob.h
index d1f3f6bc5..63391e672 100644
--- a/src/libsync/abstractnetworkjob.h
+++ b/src/libsync/abstractnetworkjob.h
@@ -128,6 +128,9 @@ protected:
QNetworkRequest req = QNetworkRequest(),
QIODevice *requestBody = nullptr);
+ QNetworkReply *sendRequest(const QByteArray &verb, const QUrl &url,
+ QNetworkRequest req, const QByteArray &requestBody);
+
// sendRequest does not take a relative path instead of an url,
// but the old API allowed that. We have this undefined overload
// to help catch usage errors
diff --git a/src/libsync/account.cpp b/src/libsync/account.cpp
index 8beb34412..d0cfe36e4 100644
--- a/src/libsync/account.cpp
+++ b/src/libsync/account.cpp
@@ -13,6 +13,8 @@
*/
#include "account.h"
+#include "accountfwd.h"
+#include "clientsideencryptionjobs.h"
#include "cookiejar.h"
#include "networkjobs.h"
#include "configfile.h"
@@ -27,6 +29,7 @@
#include "common/asserts.h"
#include "clientsideencryption.h"
+#include "ocsuserstatusconnector.h"
#include <QLoggingCategory>
#include <QNetworkReply>
@@ -43,6 +46,7 @@
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
+#include <QLoggingCategory>
#include <qsslconfiguration.h>
#include <qt5keychain/keychain.h>
@@ -93,6 +97,7 @@ QString Account::davPath() const
void Account::setSharedThis(AccountPtr sharedThis)
{
_sharedThis = sharedThis.toWeakRef();
+ setupUserStatusConnector();
}
QString Account::davPathBase()
@@ -337,6 +342,24 @@ QNetworkReply *Account::sendRawRequest(const QByteArray &verb, const QUrl &url,
return _am->sendCustomRequest(req, verb, data);
}
+QNetworkReply *Account::sendRawRequest(const QByteArray &verb, const QUrl &url, QNetworkRequest req, const QByteArray &data)
+{
+ req.setUrl(url);
+ req.setSslConfiguration(this->getOrCreateSslConfig());
+ if (verb == "HEAD" && data.isEmpty()) {
+ return _am->head(req);
+ } else if (verb == "GET" && data.isEmpty()) {
+ return _am->get(req);
+ } else if (verb == "POST") {
+ return _am->post(req, data);
+ } else if (verb == "PUT") {
+ return _am->put(req, data);
+ } else if (verb == "DELETE" && data.isEmpty()) {
+ return _am->deleteResource(req);
+ }
+ return _am->sendCustomRequest(req, verb, data);
+}
+
SimpleNetworkJob *Account::sendRequest(const QByteArray &verb, const QUrl &url, QNetworkRequest req, QIODevice *data)
{
auto job = new SimpleNetworkJob(sharedFromThis());
@@ -544,9 +567,18 @@ void Account::setCapabilities(const QVariantMap &caps)
{
_capabilities = Capabilities(caps);
+ setupUserStatusConnector();
trySetupPushNotifications();
}
+void Account::setupUserStatusConnector()
+{
+ _userStatusConnector = std::make_shared<OcsUserStatusConnector>(sharedFromThis());
+ connect(_userStatusConnector.get(), &UserStatusConnector::userStatusFetched, this, [this](const UserStatus &) {
+ emit userStatusChanged();
+ });
+}
+
QString Account::serverVersion() const
{
return _serverVersion;
@@ -744,4 +776,9 @@ PushNotifications *Account::pushNotifications() const
return _pushNotifications;
}
+std::shared_ptr<UserStatusConnector> Account::userStatusConnector() const
+{
+ return _userStatusConnector;
+}
+
} // namespace OCC
diff --git a/src/libsync/account.h b/src/libsync/account.h
index 00930b2b3..334425853 100644
--- a/src/libsync/account.h
+++ b/src/libsync/account.h
@@ -55,6 +55,7 @@ using AccountPtr = QSharedPointer<Account>;
class AccessManager;
class SimpleNetworkJob;
class PushNotifications;
+class UserStatusConnector;
/**
* @brief Reimplement this to handle SSL errors from libsync
@@ -150,6 +151,9 @@ public:
QNetworkRequest req = QNetworkRequest(),
QIODevice *data = nullptr);
+ QNetworkReply *sendRawRequest(const QByteArray &verb,
+ const QUrl &url, QNetworkRequest req, const QByteArray &data);
+
/** Create and start network job for a simple one-off request.
*
* More complicated requests typically create their own job types.
@@ -251,10 +255,13 @@ public:
// Check for the directEditing capability
void fetchDirectEditors(const QUrl &directEditingURL, const QString &directEditingETag);
+ void setupUserStatusConnector();
void trySetupPushNotifications();
PushNotifications *pushNotifications() const;
void setPushNotificationsReconnectInterval(int interval);
+ std::shared_ptr<UserStatusConnector> userStatusConnector() const;
+
public slots:
/// Used when forgetting credentials
void clearQNAMCache();
@@ -287,6 +294,8 @@ signals:
void pushNotificationsReady(Account *account);
void pushNotificationsDisabled(Account *account);
+ void userStatusChanged();
+
protected Q_SLOTS:
void slotCredentialsFetched();
void slotCredentialsAsked();
@@ -343,6 +352,8 @@ private:
PushNotifications *_pushNotifications = nullptr;
+ std::shared_ptr<UserStatusConnector> _userStatusConnector;
+
/* IMPORTANT - remove later - FIXME MS@2019-12-07 -->
* TODO: For "Log out" & "Remove account": Remove client CA certs and KEY!
*
diff --git a/src/libsync/capabilities.cpp b/src/libsync/capabilities.cpp
index 04db298b1..9983821ae 100644
--- a/src/libsync/capabilities.cpp
+++ b/src/libsync/capabilities.cpp
@@ -187,13 +187,31 @@ bool Capabilities::chunkingNg() const
return _capabilities["dav"].toMap()["chunking"].toByteArray() >= "1.0";
}
-bool Capabilities::userStatus() const
+bool Capabilities::userStatusNotification() const
{
return _capabilities.contains("notifications") &&
_capabilities["notifications"].toMap().contains("ocs-endpoints") &&
_capabilities["notifications"].toMap()["ocs-endpoints"].toStringList().contains("user-status");
}
+bool Capabilities::userStatus() const
+{
+ if (!_capabilities.contains("user_status")) {
+ return false;
+ }
+ const auto userStatusMap = _capabilities["user_status"].toMap();
+ return userStatusMap.value("enabled", false).toBool();
+}
+
+bool Capabilities::userStatusSupportsEmoji() const
+{
+ if (!userStatus()) {
+ return false;
+ }
+ const auto userStatusMap = _capabilities["user_status"].toMap();
+ return userStatusMap.value("supports_emoji", false).toBool();
+}
+
PushNotificationTypes Capabilities::availablePushNotifications() const
{
if (!_capabilities.contains("notify_push")) {
diff --git a/src/libsync/capabilities.h b/src/libsync/capabilities.h
index 078a0cd35..3040db890 100644
--- a/src/libsync/capabilities.h
+++ b/src/libsync/capabilities.h
@@ -58,7 +58,9 @@ public:
bool sharePublicLinkMultiple() const;
bool shareResharing() const;
bool chunkingNg() const;
+ bool userStatusNotification() const;
bool userStatus() const;
+ bool userStatusSupportsEmoji() const;
/// Returns which kind of push notfications are available
PushNotificationTypes availablePushNotifications() const;
diff --git a/src/libsync/clientsideencryption.cpp b/src/libsync/clientsideencryption.cpp
index 4ea561da3..2a8b1a189 100644
--- a/src/libsync/clientsideencryption.cpp
+++ b/src/libsync/clientsideencryption.cpp
@@ -56,7 +56,8 @@ Q_LOGGING_CATEGORY(lcCse, "nextcloud.sync.clientsideencryption", QtInfoMsg)
Q_LOGGING_CATEGORY(lcCseDecryption, "nextcloud.e2e", QtInfoMsg)
Q_LOGGING_CATEGORY(lcCseMetadata, "nextcloud.metadata", QtInfoMsg)
-QString baseUrl(){
+QString e2eeBaseUrl()
+{
return QStringLiteral("ocs/v2.php/apps/end_to_end_encryption/api/v1/");
}
@@ -1180,7 +1181,7 @@ void ClientSideEncryption::generateCSR(const AccountPtr &account, EVP_PKEY *keyP
qCInfo(lcCse()) << "Returning the certificate";
qCInfo(lcCse()) << output;
- auto job = new SignPublicKeyApiJob(account, baseUrl() + "public-key", this);
+ auto job = new SignPublicKeyApiJob(account, e2eeBaseUrl() + "public-key", this);
job->setCsr(output);
connect(job, &SignPublicKeyApiJob::jsonReceived, [this, account](const QJsonDocument& json, int retCode) {
@@ -1212,7 +1213,7 @@ void ClientSideEncryption::encryptPrivateKey(const AccountPtr &account)
auto cryptedText = EncryptionHelper::encryptPrivateKey(secretKey, EncryptionHelper::privateKeyToPem(_privateKey), salt);
// Send private key to the server
- auto job = new StorePrivateKeyApiJob(account, baseUrl() + "private-key", this);
+ auto job = new StorePrivateKeyApiJob(account, e2eeBaseUrl() + "private-key", this);
job->setPrivateKey(cryptedText);
connect(job, &StorePrivateKeyApiJob::jsonReceived, [this, account](const QJsonDocument& doc, int retCode) {
Q_UNUSED(doc);
@@ -1296,7 +1297,7 @@ void ClientSideEncryption::decryptPrivateKey(const AccountPtr &account, const QB
void ClientSideEncryption::getPrivateKeyFromServer(const AccountPtr &account)
{
qCInfo(lcCse()) << "Retrieving private key from server";
- auto job = new JsonApiJob(account, baseUrl() + "private-key", this);
+ auto job = new JsonApiJob(account, e2eeBaseUrl() + "private-key", this);
connect(job, &JsonApiJob::jsonReceived, [this, account](const QJsonDocument& doc, int retCode) {
if (retCode == 200) {
QString key = doc.object()["ocs"].toObject()["data"].toObject()["private-key"].toString();
@@ -1315,7 +1316,7 @@ void ClientSideEncryption::getPrivateKeyFromServer(const AccountPtr &account)
void ClientSideEncryption::getPublicKeyFromServer(const AccountPtr &account)
{
qCInfo(lcCse()) << "Retrieving public key from server";
- auto job = new JsonApiJob(account, baseUrl() + "public-key", this);
+ auto job = new JsonApiJob(account, e2eeBaseUrl() + "public-key", this);
connect(job, &JsonApiJob::jsonReceived, [this, account](const QJsonDocument& doc, int retCode) {
if (retCode == 200) {
QString publicKey = doc.object()["ocs"].toObject()["data"].toObject()["public-keys"].toObject()[account->davUser()].toString();
@@ -1336,7 +1337,7 @@ void ClientSideEncryption::getPublicKeyFromServer(const AccountPtr &account)
void ClientSideEncryption::fetchAndValidatePublicKeyFromServer(const AccountPtr &account)
{
qCInfo(lcCse()) << "Retrieving public key from server";
- auto job = new JsonApiJob(account, baseUrl() + "server-key", this);
+ auto job = new JsonApiJob(account, e2eeBaseUrl() + "server-key", this);
connect(job, &JsonApiJob::jsonReceived, [this, account](const QJsonDocument& doc, int retCode) {
if (retCode == 200) {
const auto serverPublicKey = doc.object()["ocs"].toObject()["data"].toObject()["public-key"].toString().toLatin1();
diff --git a/src/libsync/clientsideencryption.h b/src/libsync/clientsideencryption.h
index e89586451..751c7d4c8 100644
--- a/src/libsync/clientsideencryption.h
+++ b/src/libsync/clientsideencryption.h
@@ -23,7 +23,7 @@ class ReadPasswordJob;
namespace OCC {
-QString baseUrl();
+QString e2eeBaseUrl();
namespace EncryptionHelper {
QByteArray generateRandomFilename();
diff --git a/src/libsync/clientsideencryptionjobs.cpp b/src/libsync/clientsideencryptionjobs.cpp
index ad8e30c66..71bb8a510 100644
--- a/src/libsync/clientsideencryptionjobs.cpp
+++ b/src/libsync/clientsideencryptionjobs.cpp
@@ -27,7 +27,7 @@ namespace OCC {
GetMetadataApiJob::GetMetadataApiJob(const AccountPtr& account,
const QByteArray& fileId,
QObject* parent)
-: AbstractNetworkJob(account, baseUrl() + QStringLiteral("meta-data/") + fileId, parent), _fileId(fileId)
+: AbstractNetworkJob(account, e2eeBaseUrl() + QStringLiteral("meta-data/") + fileId, parent), _fileId(fileId)
{
}
@@ -63,7 +63,7 @@ StoreMetaDataApiJob::StoreMetaDataApiJob(const AccountPtr& account,
const QByteArray& fileId,
const QByteArray& b64Metadata,
QObject* parent)
-: AbstractNetworkJob(account, baseUrl() + QStringLiteral("meta-data/") + fileId, parent), _fileId(fileId), _b64Metadata(b64Metadata)
+: AbstractNetworkJob(account, e2eeBaseUrl() + QStringLiteral("meta-data/") + fileId, parent), _fileId(fileId), _b64Metadata(b64Metadata)
{
}
@@ -104,8 +104,8 @@ UpdateMetadataApiJob::UpdateMetadataApiJob(const AccountPtr& account,
const QByteArray& b64Metadata,
const QByteArray& token,
QObject* parent)
-: AbstractNetworkJob(account, baseUrl() + QStringLiteral("meta-data/") + fileId, parent),
-_fileId(fileId),
+: AbstractNetworkJob(account, e2eeBaseUrl() + QStringLiteral("meta-data/") + fileId, parent)
+, _fileId(fileId),
_b64Metadata(b64Metadata),
_token(token)
{
@@ -154,7 +154,7 @@ UnlockEncryptFolderApiJob::UnlockEncryptFolderApiJob(const AccountPtr& account,
const QByteArray& fileId,
const QByteArray& token,
QObject* parent)
-: AbstractNetworkJob(account, baseUrl() + QStringLiteral("lock/") + fileId, parent), _fileId(fileId), _token(token)
+: AbstractNetworkJob(account, e2eeBaseUrl() + QStringLiteral("lock/") + fileId, parent), _fileId(fileId), _token(token)
{
}
@@ -185,11 +185,10 @@ bool UnlockEncryptFolderApiJob::finished()
}
-
DeleteMetadataApiJob::DeleteMetadataApiJob(const AccountPtr& account,
const QByteArray& fileId,
QObject* parent)
-: AbstractNetworkJob(account, baseUrl() + QStringLiteral("meta-data/") + fileId, parent), _fileId(fileId)
+: AbstractNetworkJob(account, e2eeBaseUrl() + QStringLiteral("meta-data/") + fileId, parent), _fileId(fileId)
{
}
@@ -219,7 +218,7 @@ bool DeleteMetadataApiJob::finished()
}
LockEncryptFolderApiJob::LockEncryptFolderApiJob(const AccountPtr& account, const QByteArray& fileId, QObject* parent)
-: AbstractNetworkJob(account, baseUrl() + QStringLiteral("lock/") + fileId, parent), _fileId(fileId)
+: AbstractNetworkJob(account, e2eeBaseUrl() + QStringLiteral("lock/") + fileId, parent), _fileId(fileId)
{
}
@@ -258,7 +257,7 @@ bool LockEncryptFolderApiJob::finished()
}
SetEncryptionFlagApiJob::SetEncryptionFlagApiJob(const AccountPtr& account, const QByteArray& fileId, FlagAction flagAction, QObject* parent)
-: AbstractNetworkJob(account, baseUrl() + QStringLiteral("encrypted/") + fileId, parent), _fileId(fileId), _flagAction(flagAction)
+: AbstractNetworkJob(account, e2eeBaseUrl() + QStringLiteral("encrypted/") + fileId, parent), _fileId(fileId), _flagAction(flagAction)
{
}
diff --git a/src/libsync/datetimeprovider.cpp b/src/libsync/datetimeprovider.cpp
new file mode 100644
index 000000000..084072312
--- /dev/null
+++ b/src/libsync/datetimeprovider.cpp
@@ -0,0 +1,17 @@
+#include "datetimeprovider.h"
+
+namespace OCC {
+
+DateTimeProvider::~DateTimeProvider() = default;
+
+QDateTime DateTimeProvider::currentDateTime() const
+{
+ return QDateTime::currentDateTime();
+}
+
+QDate DateTimeProvider::currentDate() const
+{
+ return QDate::currentDate();
+}
+
+}
diff --git a/src/libsync/datetimeprovider.h b/src/libsync/datetimeprovider.h
new file mode 100644
index 000000000..1525a2e3d
--- /dev/null
+++ b/src/libsync/datetimeprovider.h
@@ -0,0 +1,18 @@
+#pragma once
+
+#include "owncloudlib.h"
+
+#include <QDateTime>
+
+namespace OCC {
+
+class OWNCLOUDSYNC_EXPORT DateTimeProvider
+{
+public:
+ virtual ~DateTimeProvider();
+
+ virtual QDateTime currentDateTime() const;
+
+ virtual QDate currentDate() const;
+};
+}
diff --git a/src/libsync/networkjobs.cpp b/src/libsync/networkjobs.cpp
index 9224afc76..2800af0d6 100644
--- a/src/libsync/networkjobs.cpp
+++ b/src/libsync/networkjobs.cpp
@@ -830,13 +830,49 @@ void JsonApiJob::addRawHeader(const QByteArray &headerName, const QByteArray &va
_request.setRawHeader(headerName, value);
}
+void JsonApiJob::setBody(const QJsonDocument &body)
+{
+ _body = body.toJson();
+ qCDebug(lcJsonApiJob) << "Set body for request:" << _body;
+ if (!_body.isEmpty()) {
+ _request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
+ }
+}
+
+
+void JsonApiJob::setVerb(Verb value)
+{
+ _verb = value;
+}
+
+
+QByteArray JsonApiJob::verbToString() const
+{
+ switch (_verb) {
+ case Verb::Get:
+ return "GET";
+ case Verb::Post:
+ return "POST";
+ case Verb::Put:
+ return "PUT";
+ case Verb::Delete:
+ return "DELETE";
+ }
+ return "GET";
+}
+
void JsonApiJob::start()
{
addRawHeader("OCS-APIREQUEST", "true");
auto query = _additionalParams;
query.addQueryItem(QLatin1String("format"), QLatin1String("json"));
QUrl url = Utility::concatUrlPath(account()->url(), path(), query);
- sendRequest(_usePOST ? "POST" : "GET", url, _request);
+ const auto httpVerb = verbToString();
+ if (!_body.isEmpty()) {
+ sendRequest(httpVerb, url, _request, _body);
+ } else {
+ sendRequest(httpVerb, url, _request);
+ }
AbstractNetworkJob::start();
}
diff --git a/src/libsync/networkjobs.h b/src/libsync/networkjobs.h
index 45fb12a22..01cfcdedd 100644
--- a/src/libsync/networkjobs.h
+++ b/src/libsync/networkjobs.h
@@ -22,6 +22,7 @@
#include <QBuffer>
#include <QUrlQuery>
+#include <QJsonDocument>
#include <functional>
class QUrl;
@@ -375,6 +376,13 @@ class OWNCLOUDSYNC_EXPORT JsonApiJob : public AbstractNetworkJob
{
Q_OBJECT
public:
+ enum class Verb {
+ Get,
+ Post,
+ Put,
+ Delete,
+ };
+
explicit JsonApiJob(const AccountPtr &account, const QString &path, QObject *parent = nullptr);
/**
@@ -390,15 +398,9 @@ public:
void addQueryParams(const QUrlQuery &params);
void addRawHeader(const QByteArray &headerName, const QByteArray &value);
- /**
- * @brief usePOST - allow job to do an anonymous POST request instead of GET
- * @param params: (optional) true for POST, false for GET (default).
- *
- * This function needs to be called before start() obviously.
- */
- void usePOST(bool usePOST = true) {
- _usePOST = usePOST;
- }
+ void setBody(const QJsonDocument &body);
+
+ void setVerb(Verb value);
public slots:
void start() override;
@@ -429,10 +431,13 @@ signals:
void allowDesktopNotificationsChanged(bool isAllowed);
private:
+ QByteArray _body;
QUrlQuery _additionalParams;
QNetworkRequest _request;
- bool _usePOST = false;
+ Verb _verb = Verb::Get;
+
+ QByteArray verbToString() const;
};
/**
diff --git a/src/libsync/ocsuserstatusconnector.cpp b/src/libsync/ocsuserstatusconnector.cpp
new file mode 100644
index 000000000..95f3810e2
--- /dev/null
+++ b/src/libsync/ocsuserstatusconnector.cpp
@@ -0,0 +1,455 @@
+/*
+ * Copyright (C) by Felix Weilbach <felix.weilbach@nextcloud.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "ocsuserstatusconnector.h"
+#include "account.h"
+#include "userstatusconnector.h"
+
+#include <networkjobs.h>
+
+#include <QDateTime>
+#include <QtGlobal>
+#include <QJsonDocument>
+#include <QJsonValue>
+#include <QLoggingCategory>
+#include <QString>
+#include <QJsonObject>
+#include <QJsonArray>
+#include <qdatetime.h>
+#include <qjsonarray.h>
+#include <qjsonobject.h>
+#include <qloggingcategory.h>
+
+namespace {
+
+Q_LOGGING_CATEGORY(lcOcsUserStatusConnector, "nextcloud.gui.ocsuserstatusconnector", QtInfoMsg)
+
+OCC::UserStatus::OnlineStatus stringToUserOnlineStatus(const QString &status)
+{
+ // it needs to match the Status enum
+ const QHash<QString, OCC::UserStatus::OnlineStatus> preDefinedStatus {
+ { "online", OCC::UserStatus::OnlineStatus::Online },
+ { "dnd", OCC::UserStatus::OnlineStatus::DoNotDisturb },
+ { "away", OCC::UserStatus::OnlineStatus::Away },
+ { "offline", OCC::UserStatus::OnlineStatus::Offline },
+ { "invisible", OCC::UserStatus::OnlineStatus::Invisible }
+ };
+
+ // api should return invisible, dnd,... toLower() it is to make sure
+ // it matches _preDefinedStatus, otherwise the default is online (0)
+ return preDefinedStatus.value(status.toLower(), OCC::UserStatus::OnlineStatus::Online);
+}
+
+QString onlineStatusToString(OCC::UserStatus::OnlineStatus status)
+{
+ switch (status) {
+ case OCC::UserStatus::OnlineStatus::Online:
+ return QStringLiteral("online");
+ case OCC::UserStatus::OnlineStatus::DoNotDisturb:
+ return QStringLiteral("dnd");
+ case OCC::UserStatus::OnlineStatus::Away:
+ return QStringLiteral("offline");
+ case OCC::UserStatus::OnlineStatus::Offline:
+ return QStringLiteral("offline");
+ case OCC::UserStatus::OnlineStatus::Invisible:
+ return QStringLiteral("invisible");
+ }
+ return QStringLiteral("online");
+}
+
+OCC::Optional<OCC::ClearAt> jsonExtractClearAt(QJsonObject jsonObject)
+{
+ OCC::Optional<OCC::ClearAt> clearAt {};
+ if (jsonObject.contains("clearAt") && !jsonObject.value("clearAt").isNull()) {
+ OCC::ClearAt clearAtValue;
+ clearAtValue._type = OCC::ClearAtType::Timestamp;
+ clearAtValue._timestamp = jsonObject.value("clearAt").toInt();
+ clearAt = clearAtValue;
+ }
+ return clearAt;
+}
+
+OCC::UserStatus jsonExtractUserStatus(QJsonObject json)
+{
+ const auto clearAt = jsonExtractClearAt(json);
+
+ const OCC::UserStatus userStatus(json.value("messageId").toString(),
+ json.value("message").toString().trimmed(),
+ json.value("icon").toString().trimmed(), stringToUserOnlineStatus(json.value("status").toString()),
+ json.value("messageIsPredefined").toBool(false), clearAt);
+
+ return userStatus;
+}
+
+OCC::UserStatus jsonToUserStatus(const QJsonDocument &json)
+{
+ const QJsonObject defaultValues {
+ { "icon", "" },
+ { "message", "" },
+ { "status", "online" },
+ { "messageIsPredefined", "false" },
+ { "statusIsUserDefined", "false" }
+ };
+ const auto retrievedData = json.object().value("ocs").toObject().value("data").toObject(defaultValues);
+ return jsonExtractUserStatus(retrievedData);
+}
+
+quint64 clearAtEndOfToTimestamp(const OCC::ClearAt &clearAt)
+{
+ Q_ASSERT(clearAt._type == OCC::ClearAtType::EndOf);
+
+ if (clearAt._endof == "day") {
+ return QDate::currentDate().addDays(1).startOfDay().toTime_t();
+ } else if (clearAt._endof == "week") {
+ const auto days = Qt::Sunday - QDate::currentDate().dayOfWeek();
+ return QDate::currentDate().addDays(days + 1).startOfDay().toTime_t();
+ }
+ qCWarning(lcOcsUserStatusConnector) << "Can not handle clear at endof day type" << clearAt._endof;
+ return QDateTime::currentDateTime().toTime_t();
+}
+
+quint64 clearAtPeriodToTimestamp(const OCC::ClearAt &clearAt)
+{
+ return QDateTime::currentDateTime().addSecs(clearAt._period).toTime_t();
+}
+
+quint64 clearAtToTimestamp(const OCC::ClearAt &clearAt)
+{
+ switch (clearAt._type) {
+ case OCC::ClearAtType::Period: {
+ return clearAtPeriodToTimestamp(clearAt);
+ }
+
+ case OCC::ClearAtType::EndOf: {
+ return clearAtEndOfToTimestamp(clearAt);
+ }
+
+ case OCC::ClearAtType::Timestamp: {
+ return clearAt._timestamp;
+ }
+ }
+
+ return 0;
+}
+
+quint64 clearAtToTimestamp(const OCC::Optional<OCC::ClearAt> &clearAt)
+{
+ if (clearAt) {
+ return clearAtToTimestamp(*clearAt);
+ }
+ return 0;
+}
+
+OCC::Optional<OCC::ClearAt> jsonToClearAt(QJsonObject jsonObject)
+{
+ OCC::Optional<OCC::ClearAt> clearAt;
+
+ if (jsonObject.value("clearAt").isObject() && !jsonObject.value("clearAt").isNull()) {
+ OCC::ClearAt clearAtValue;
+ const auto clearAtObject = jsonObject.value("clearAt").toObject();
+ const auto typeValue = clearAtObject.value("type").toString("period");
+ if (typeValue == "period") {
+ const auto timeValue = clearAtObject.value("time").toInt(0);
+ clearAtValue._type = OCC::ClearAtType::Period;
+ clearAtValue._period = timeValue;
+ } else if (typeValue == "end-of") {
+ const auto timeValue = clearAtObject.value("time").toString("day");
+ clearAtValue._type = OCC::ClearAtType::EndOf;
+ clearAtValue._endof = timeValue;
+ } else {
+ qCWarning(lcOcsUserStatusConnector) << "Can not handle clear type value" << typeValue;
+ }
+ clearAt = clearAtValue;
+ }
+
+ return clearAt;
+}
+
+OCC::UserStatus jsonToUserStatus(QJsonObject jsonObject)
+{
+ const auto clearAt = jsonToClearAt(jsonObject);
+
+ OCC::UserStatus userStatus(
+ jsonObject.value("id").toString("no-id"),
+ jsonObject.value("message").toString("No message"),
+ jsonObject.value("icon").toString("no-icon"),
+ OCC::UserStatus::OnlineStatus::Online,
+ true,
+ clearAt);
+
+ return userStatus;
+}
+
+std::vector<OCC::UserStatus> jsonToPredefinedStatuses(QJsonArray jsonDataArray)
+{
+ std::vector<OCC::UserStatus> statuses;
+ for (const auto &jsonEntry : jsonDataArray) {
+ Q_ASSERT(jsonEntry.isObject());
+ if (!jsonEntry.isObject()) {
+ continue;
+ }
+ statuses.push_back(jsonToUserStatus(jsonEntry.toObject()));
+ }
+
+ return statuses;
+}
+
+
+const QString baseUrl("/ocs/v2.php/apps/user_status/api/v1");
+const QString userStatusBaseUrl = baseUrl + QStringLiteral("/user_status");
+}
+
+namespace OCC {
+
+OcsUserStatusConnector::OcsUserStatusConnector(AccountPtr account, QObject *parent)
+ : UserStatusConnector(parent)
+ , _account(account)
+{
+ Q_ASSERT(_account);
+ _userStatusSupported = _account->capabilities().userStatus();
+ _userStatusEmojisSupported = _account->capabilities().userStatusSupportsEmoji();
+}
+
+void OcsUserStatusConnector::fetchUserStatus()
+{
+ qCDebug(lcOcsUserStatusConnector) << "Try to fetch user status";
+
+ if (!_userStatusSupported) {
+ qCDebug(lcOcsUserStatusConnector) << "User status not supported";
+ emit error(Error::UserStatusNotSupported);
+ return;
+ }
+
+ startFetchUserStatusJob();
+}
+
+void OcsUserStatusConnector::startFetchUserStatusJob()
+{
+ if (_getUserStatusJob) {
+ qCDebug(lcOcsUserStatusConnector) << "Get user status job is already running.";
+ return;
+ }
+
+ _getUserStatusJob = new JsonApiJob(_account, userStatusBaseUrl, this);
+ connect(_getUserStatusJob, &JsonApiJob::jsonReceived, this, &OcsUserStatusConnector::onUserStatusFetched);
+ _getUserStatusJob->start();
+}
+
+void OcsUserStatusConnector::onUserStatusFetched(const QJsonDocument &json, int statusCode)
+{
+ logResponse("user status fetched", json, statusCode);
+
+ if (statusCode != 200) {
+ qCInfo(lcOcsUserStatusConnector) << "Slot fetch UserStatus finished with status code" << statusCode;
+ emit error(Error::CouldNotFetchUserStatus);
+ return;
+ }
+
+ _userStatus = jsonToUserStatus(json);
+ emit userStatusFetched(_userStatus);
+}
+
+void OcsUserStatusConnector::startFetchPredefinedStatuses()
+{
+ if (_getPredefinedStausesJob) {
+ qCDebug(lcOcsUserStatusConnector) << "Get predefined statuses job is already running";
+ return;
+ }
+
+ _getPredefinedStausesJob = new JsonApiJob(_account,
+ baseUrl + QStringLiteral("/predefined_statuses"), this);
+ connect(_getPredefinedStausesJob, &JsonApiJob::jsonReceived, this,
+ &OcsUserStatusConnector::onPredefinedStatusesFetched);
+ _getPredefinedStausesJob->start();
+}
+
+void OcsUserStatusConnector::fetchPredefinedStatuses()
+{
+ if (!_userStatusSupported) {
+ emit error(Error::UserStatusNotSupported);
+ return;
+ }
+ startFetchPredefinedStatuses();
+}
+
+void OcsUserStatusConnector::onPredefinedStatusesFetched(const QJsonDocument &json, int statusCode)
+{
+ logResponse("predefined statuses", json, statusCode);
+
+ if (statusCode != 200) {
+ qCInfo(lcOcsUserStatusConnector) << "Slot predefined user statuses finished with status code" << statusCode;
+ emit error(Error::CouldNotFetchPredefinedUserStatuses);
+ return;
+ }
+ const auto jsonData = json.object().value("ocs").toObject().value("data");
+ Q_ASSERT(jsonData.isArray());
+ if (!jsonData.isArray()) {
+ return;
+ }
+ const auto statuses = jsonToPredefinedStatuses(jsonData.toArray());
+ emit predefinedStatusesFetched(statuses);
+}
+
+void OcsUserStatusConnector::logResponse(const QString &message, const QJsonDocument &json, int statusCode)
+{
+ qCDebug(lcOcsUserStatusConnector) << "Response from:" << message << "Status:" << statusCode << "Json:" << json;
+}
+
+void OcsUserStatusConnector::setUserStatusOnlineStatus(UserStatus::OnlineStatus onlineStatus)
+{
+ _setOnlineStatusJob = new JsonApiJob(_account,
+ userStatusBaseUrl + QStringLiteral("/status"), this);
+ _setOnlineStatusJob->setVerb(JsonApiJob::Verb::Put);
+ // Set body
+ QJsonObject dataObject;
+ dataObject.insert("statusType", onlineStatusToString(onlineStatus));
+ QJsonDocument body;
+ body.setObject(dataObject);
+ _setOnlineStatusJob->setBody(body);
+ connect(_setOnlineStatusJob, &JsonApiJob::jsonReceived, this, &OcsUserStatusConnector::onUserStatusOnlineStatusSet);
+ _setOnlineStatusJob->start();
+}
+
+void OcsUserStatusConnector::setUserStatusMessagePredefined(const UserStatus &userStatus)
+{
+ Q_ASSERT(userStatus.messagePredefined());
+ if (!userStatus.messagePredefined()) {
+ return;
+ }
+
+ _setMessageJob = new JsonApiJob(_account, userStatusBaseUrl + QStringLiteral("/message/predefined"), this);
+ _setMessageJob->setVerb(JsonApiJob::Verb::Put);
+ // Set body
+ QJsonObject dataObject;
+ dataObject.insert("messageId", userStatus.id());
+ if (userStatus.clearAt()) {
+ dataObject.insert("clearAt", static_cast<int>(clearAtToTimestamp(userStatus.clearAt())));
+ } else {
+ dataObject.insert("clearAt", QJsonValue());
+ }
+ QJsonDocument body;
+ body.setObject(dataObject);
+ _setMessageJob->setBody(body);
+ connect(_setMessageJob, &JsonApiJob::jsonReceived, this, &OcsUserStatusConnector::onUserStatusMessageSet);
+ _setMessageJob->start();
+}
+
+void OcsUserStatusConnector::setUserStatusMessageCustom(const UserStatus &userStatus)
+{
+ Q_ASSERT(!userStatus.messagePredefined());
+ if (userStatus.messagePredefined()) {
+ return;
+ }
+
+ if (!_userStatusEmojisSupported) {
+ emit error(Error::EmojisNotSupported);
+ return;
+ }
+ _setMessageJob = new JsonApiJob(_account, userStatusBaseUrl + QStringLiteral("/message/custom"), this);
+ _setMessageJob->setVerb(JsonApiJob::Verb::Put);
+ // Set body
+ QJsonObject dataObject;
+ dataObject.insert("statusIcon", userStatus.icon());
+ dataObject.insert("message", userStatus.message());
+ const auto clearAt = userStatus.clearAt();
+ if (clearAt) {
+ dataObject.insert("clearAt", static_cast<int>(clearAtToTimestamp(*clearAt)));
+ } else {
+ dataObject.insert("clearAt", QJsonValue());
+ }
+ QJsonDocument body;
+ body.setObject(dataObject);
+ _setMessageJob->setBody(body);
+ connect(_setMessageJob, &JsonApiJob::jsonReceived, this, &OcsUserStatusConnector::onUserStatusMessageSet);
+ _setMessageJob->start();
+}
+
+void OcsUserStatusConnector::setUserStatusMessage(const UserStatus &userStatus)
+{
+ if (userStatus.messagePredefined()) {
+ setUserStatusMessagePredefined(userStatus);
+ return;
+ }
+ setUserStatusMessageCustom(userStatus);
+}
+
+void OcsUserStatusConnector::setUserStatus(const UserStatus &userStatus)
+{
+ if (!_userStatusSupported) {
+ emit error(Error::UserStatusNotSupported);
+ return;
+ }
+
+ if (_setOnlineStatusJob || _setMessageJob) {
+ qCDebug(lcOcsUserStatusConnector) << "Set online status job or set message job are already running.";
+ return;
+ }
+
+ setUserStatusOnlineStatus(userStatus.state());
+ setUserStatusMessage(userStatus);
+}
+
+void OcsUserStatusConnector::onUserStatusOnlineStatusSet(const QJsonDocument &json, int statusCode)
+{
+ logResponse("Online status set", json, statusCode);
+
+ if (statusCode != 200) {
+ emit error(Error::CouldNotSetUserStatus);
+ return;
+ }
+}
+
+void OcsUserStatusConnector::onUserStatusMessageSet(const QJsonDocument &json, int statusCode)
+{
+ logResponse("Message set", json, statusCode);
+
+ if (statusCode != 200) {
+ emit error(Error::CouldNotSetUserStatus);
+ return;
+ }
+
+ // We fetch the user status again because json does not contain
+ // the new message when user status was set from a predefined
+ // message
+ fetchUserStatus();
+
+ emit userStatusSet();
+}
+
+void OcsUserStatusConnector::clearMessage()
+{
+ _clearMessageJob = new JsonApiJob(_account, userStatusBaseUrl + QStringLiteral("/message"));
+ _clearMessageJob->setVerb(JsonApiJob::Verb::Delete);
+ connect(_clearMessageJob, &JsonApiJob::jsonReceived, this, &OcsUserStatusConnector::onMessageCleared);
+ _clearMessageJob->start();
+}
+
+UserStatus OcsUserStatusConnector::userStatus() const
+{
+ return _userStatus;
+}
+
+void OcsUserStatusConnector::onMessageCleared(const QJsonDocument &json, int statusCode)
+{
+ logResponse("Message cleared", json, statusCode);
+
+ if (statusCode != 200) {
+ emit error(Error::CouldNotClearMessage);
+ return;
+ }
+
+ _userStatus = {};
+ emit messageCleared();
+}
+}
diff --git a/src/libsync/ocsuserstatusconnector.h b/src/libsync/ocsuserstatusconnector.h
new file mode 100644
index 000000000..0d366419f
--- /dev/null
+++ b/src/libsync/ocsuserstatusconnector.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) by Felix Weilbach <felix.weilbach@nextcloud.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#pragma once
+
+#include "accountfwd.h"
+#include "userstatusconnector.h"
+
+#include <QPointer>
+
+namespace OCC {
+
+class JsonApiJob;
+class SimpleNetworkJob;
+
+class OWNCLOUDSYNC_EXPORT OcsUserStatusConnector : public UserStatusConnector
+{
+public:
+ explicit OcsUserStatusConnector(AccountPtr account, QObject *parent = nullptr);
+
+ void fetchUserStatus() override;
+
+ void fetchPredefinedStatuses() override;
+
+ void setUserStatus(const UserStatus &userStatus) override;
+
+ void clearMessage() override;
+
+ UserStatus userStatus() const override;
+
+private:
+ void onUserStatusFetched(const QJsonDocument &json, int statusCode);
+ void onPredefinedStatusesFetched(const QJsonDocument &json, int statusCode);
+ void onUserStatusOnlineStatusSet(const QJsonDocument &json, int statusCode);
+ void onUserStatusMessageSet(const QJsonDocument &json, int statusCode);
+ void onMessageCleared(const QJsonDocument &json, int statusCode);
+
+ void logResponse(const QString &message, const QJsonDocument &json, int statusCode);
+ void startFetchUserStatusJob();
+ void startFetchPredefinedStatuses();
+ void setUserStatusOnlineStatus(UserStatus::OnlineStatus onlineStatus);
+ void setUserStatusMessage(const UserStatus &userStatus);
+ void setUserStatusMessagePredefined(const UserStatus &userStatus);
+ void setUserStatusMessageCustom(const UserStatus &userStatus);
+
+ AccountPtr _account;
+
+ bool _userStatusSupported = false;
+ bool _userStatusEmojisSupported = false;
+
+ QPointer<JsonApiJob> _clearMessageJob {};
+ QPointer<JsonApiJob> _setMessageJob {};
+ QPointer<JsonApiJob> _setOnlineStatusJob {};
+ QPointer<JsonApiJob> _getPredefinedStausesJob {};
+ QPointer<JsonApiJob> _getUserStatusJob {};
+
+ UserStatus _userStatus;
+};
+}
diff --git a/src/libsync/userstatusconnector.cpp b/src/libsync/userstatusconnector.cpp
new file mode 100644
index 000000000..178e8d794
--- /dev/null
+++ b/src/libsync/userstatusconnector.cpp
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) by Felix Weilbach <felix.weilbach@nextcloud.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "userstatusconnector.h"
+#include "theme.h"
+
+namespace OCC {
+
+UserStatus::UserStatus() = default;
+
+UserStatus::UserStatus(
+ const QString &id, const QString &message, const QString &icon,
+ OnlineStatus state, bool messagePredefined, const Optional<ClearAt> &clearAt)
+ : _id(id)
+ , _message(message)
+ , _icon(icon)
+ , _state(state)
+ , _messagePredefined(messagePredefined)
+ , _clearAt(clearAt)
+{
+}
+
+QString UserStatus::id() const
+{
+ return _id;
+}
+
+QString UserStatus::message() const
+{
+ return _message;
+}
+
+QString UserStatus::icon() const
+{
+ return _icon;
+}
+
+auto UserStatus::state() const -> OnlineStatus
+{
+ return _state;
+}
+
+bool UserStatus::messagePredefined() const
+{
+ return _messagePredefined;
+}
+
+QUrl UserStatus::stateIcon() const
+{
+ switch (_state) {
+ case UserStatus::OnlineStatus::Away:
+ return Theme::instance()->statusAwayImageSource();
+
+ case UserStatus::OnlineStatus::DoNotDisturb:
+ return Theme::instance()->statusDoNotDisturbImageSource();
+
+ case UserStatus::OnlineStatus::Invisible:
+ case UserStatus::OnlineStatus::Offline:
+ return Theme::instance()->statusInvisibleImageSource();
+
+ case UserStatus::OnlineStatus::Online:
+ return Theme::instance()->statusOnlineImageSource();
+ }
+
+ Q_UNREACHABLE();
+}
+
+Optional<ClearAt> UserStatus::clearAt() const
+{
+ return _clearAt;
+}
+
+void UserStatus::setId(const QString &id)
+{
+ _id = id;
+}
+
+void UserStatus::setMessage(const QString &message)
+{
+ _message = message;
+}
+
+void UserStatus::setState(OnlineStatus state)
+{
+ _state = state;
+}
+
+void UserStatus::setIcon(const QString &icon)
+{
+ _icon = icon;
+}
+
+void UserStatus::setMessagePredefined(bool value)
+{
+ _messagePredefined = value;
+}
+
+void UserStatus::setClearAt(const Optional<ClearAt> &dateTime)
+{
+ _clearAt = dateTime;
+}
+
+
+UserStatusConnector::UserStatusConnector(QObject *parent)
+ : QObject(parent)
+{
+}
+
+UserStatusConnector::~UserStatusConnector() = default;
+}
diff --git a/src/libsync/userstatusconnector.h b/src/libsync/userstatusconnector.h
new file mode 100644
index 000000000..d5593fe9e
--- /dev/null
+++ b/src/libsync/userstatusconnector.h
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) by Felix Weilbach <felix.weilbach@nextcloud.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#pragma once
+
+#include "common/result.h"
+#include "owncloudlib.h"
+
+#include <QObject>
+#include <QString>
+#include <QMetaType>
+#include <QUrl>
+#include <QDateTime>
+#include <QtGlobal>
+#include <QVariant>
+
+#include <vector>
+
+
+namespace OCC {
+
+enum class OWNCLOUDSYNC_EXPORT ClearAtType {
+ Period,
+ EndOf,
+ Timestamp
+};
+
+// TODO: If we can use C++17 make it a std::variant
+struct OWNCLOUDSYNC_EXPORT ClearAt
+{
+ ClearAtType _type = ClearAtType::Period;
+
+ quint64 _timestamp;
+ int _period;
+ QString _endof;
+};
+
+class OWNCLOUDSYNC_EXPORT UserStatus
+{
+ Q_GADGET
+
+ Q_PROPERTY(QString id MEMBER _id)
+ Q_PROPERTY(QString message MEMBER _message)
+ Q_PROPERTY(QString icon MEMBER _icon)
+ Q_PROPERTY(OnlineStatus state MEMBER _state)
+
+public:
+ enum class OnlineStatus : quint8 {
+ Online,
+ DoNotDisturb,
+ Away,
+ Offline,
+ Invisible
+ };
+ Q_ENUM(OnlineStatus);
+
+ UserStatus();
+
+ UserStatus(const QString &id, const QString &message, const QString &icon,
+ OnlineStatus state, bool messagePredefined, const Optional<ClearAt> &clearAt = {});
+
+ Q_REQUIRED_RESULT QString id() const;
+ Q_REQUIRED_RESULT QString message() const;
+ Q_REQUIRED_RESULT QString icon() const;
+ Q_REQUIRED_RESULT OnlineStatus state() const;
+ Q_REQUIRED_RESULT Optional<ClearAt> clearAt() const;
+
+ void setId(const QString &id);
+ void setMessage(const QString &message);
+ void setState(OnlineStatus state);
+ void setIcon(const QString &icon);
+ void setMessagePredefined(bool value);
+ void setClearAt(const Optional<ClearAt> &dateTime);
+
+ Q_REQUIRED_RESULT bool messagePredefined() const;
+
+ Q_REQUIRED_RESULT QUrl stateIcon() const;
+
+private:
+ QString _id;
+ QString _message;
+ QString _icon;
+ OnlineStatus _state = OnlineStatus::Online;
+ bool _messagePredefined;
+ Optional<ClearAt> _clearAt;
+};
+
+class OWNCLOUDSYNC_EXPORT UserStatusConnector : public QObject
+{
+ Q_OBJECT
+
+public:
+ enum class Error {
+ CouldNotFetchUserStatus,
+ CouldNotFetchPredefinedUserStatuses,
+ UserStatusNotSupported,
+ EmojisNotSupported,
+ CouldNotSetUserStatus,
+ CouldNotClearMessage
+ };
+ Q_ENUM(Error)
+
+ explicit UserStatusConnector(QObject *parent = nullptr);
+
+ ~UserStatusConnector() override;
+
+ virtual void fetchUserStatus() = 0;
+
+ virtual void fetchPredefinedStatuses() = 0;
+
+ virtual void setUserStatus(const UserStatus &userStatus) = 0;
+
+ virtual void clearMessage() = 0;
+
+ virtual UserStatus userStatus() const = 0;
+
+signals:
+ void userStatusFetched(const UserStatus &userStatus);
+ void predefinedStatusesFetched(const std::vector<UserStatus> &statuses);
+ void userStatusSet();
+ void messageCleared();
+ void error(Error error);
+};
+}
+
+Q_DECLARE_METATYPE(OCC::UserStatusConnector *)
+Q_DECLARE_METATYPE(OCC::UserStatus)
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 924520941..1197d1cbd 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -59,6 +59,7 @@ nextcloud_add_test(PushNotifications)
nextcloud_add_test(Theme)
nextcloud_add_test(IconUtils)
nextcloud_add_test(NotificationCache)
+nextcloud_add_test(SetUserStatusDialog)
if( UNIX AND NOT APPLE )
nextcloud_add_test(InotifyWatcher)
diff --git a/test/testcapabilities.cpp b/test/testcapabilities.cpp
index 1d85d0a37..05259f8f6 100644
--- a/test/testcapabilities.cpp
+++ b/test/testcapabilities.cpp
@@ -138,6 +138,82 @@ private slots:
QCOMPARE(capabilities.pushNotificationsWebSocketUrl(), websocketUrl);
}
+
+ void testUserStatus_userStatusAvailable_returnTrue()
+ {
+ QVariantMap userStatusMap;
+ userStatusMap["enabled"] = true;
+
+ QVariantMap capabilitiesMap;
+ capabilitiesMap["user_status"] = userStatusMap;
+
+ const OCC::Capabilities capabilities(capabilitiesMap);
+
+ QVERIFY(capabilities.userStatus());
+ }
+
+ void testUserStatus_userStatusNotAvailable_returnFalse()
+ {
+ QVariantMap userStatusMap;
+ userStatusMap["enabled"] = false;
+
+ QVariantMap capabilitiesMap;
+ capabilitiesMap["user_status"] = userStatusMap;
+
+ const OCC::Capabilities capabilities(capabilitiesMap);
+
+ QVERIFY(!capabilities.userStatus());
+ }
+
+ void testUserStatus_userStatusNotInCapabilites_returnFalse()
+ {
+ QVariantMap capabilitiesMap;
+
+ const OCC::Capabilities capabilities(capabilitiesMap);
+
+ QVERIFY(!capabilities.userStatus());
+ }
+
+ void testUserStatusSupportsEmoji_supportsEmojiAvailable_returnTrue()
+ {
+ QVariantMap userStatusMap;
+ userStatusMap["enabled"] = true;
+ userStatusMap["supports_emoji"] = true;
+
+ QVariantMap capabilitiesMap;
+ capabilitiesMap["user_status"] = userStatusMap;
+
+ const OCC::Capabilities capabilities(capabilitiesMap);
+
+ QVERIFY(capabilities.userStatus());
+ }
+
+ void testUserStatusSupportsEmoji_supportsEmojiNotAvailable_returnFalse()
+ {
+ QVariantMap userStatusMap;
+ userStatusMap["enabled"] = true;
+ userStatusMap["supports_emoji"] = false;
+
+ QVariantMap capabilitiesMap;
+ capabilitiesMap["user_status"] = userStatusMap;
+
+ const OCC::Capabilities capabilities(capabilitiesMap);
+
+ QVERIFY(!capabilities.userStatusSupportsEmoji());
+ }
+
+ void testUserStatusSupportsEmoji_supportsEmojiNotInCapabilites_returnFalse()
+ {
+ QVariantMap userStatusMap;
+ userStatusMap["enabled"] = true;
+
+ QVariantMap capabilitiesMap;
+ capabilitiesMap["user_status"] = userStatusMap;
+
+ const OCC::Capabilities capabilities(capabilitiesMap);
+
+ QVERIFY(!capabilities.userStatusSupportsEmoji());
+ }
};
QTEST_GUILESS_MAIN(TestCapabilities)
diff --git a/test/testpushnotifications.cpp b/test/testpushnotifications.cpp
index b7e00583f..9345918e5 100644
--- a/test/testpushnotifications.cpp
+++ b/test/testpushnotifications.cpp
@@ -65,6 +65,20 @@ class TestPushNotifications : public QObject
Q_OBJECT
private slots:
+ void testTryReconnect_capabilitesReportPushNotificationsAvailable_reconnectForEver()
+ {
+ FakeWebSocketServer fakeServer;
+ auto account = FakeWebSocketServer::createAccount();
+ account->setPushNotificationsReconnectInterval(0);
+
+ // Let if fail a few times
+ QVERIFY(failThreeAuthenticationAttempts(fakeServer, account));
+ QVERIFY(failThreeAuthenticationAttempts(fakeServer, account));
+
+ // Push notifications should try to reconnect
+ QVERIFY(fakeServer.authenticateAccount(account));
+ }
+
void testSetup_correctCredentials_authenticateAndEmitReady()
{
FakeWebSocketServer fakeServer;
@@ -272,20 +286,6 @@ private slots:
QVERIFY(verifyCalledOnceWithAccount(*activitiesChangedSpy, account));
}));
}
-
- void testTryReconnect_capabilitesReportPushNotificationsAvailable_reconnectForEver()
- {
- FakeWebSocketServer fakeServer;
- auto account = FakeWebSocketServer::createAccount();
- account->setPushNotificationsReconnectInterval(0);
-
- // Let if fail a few times
- QVERIFY(failThreeAuthenticationAttempts(fakeServer, account));
- QVERIFY(failThreeAuthenticationAttempts(fakeServer, account));
-
- // Push notifications should try to reconnect
- QVERIFY(fakeServer.authenticateAccount(account));
- }
};
QTEST_GUILESS_MAIN(TestPushNotifications)
diff --git a/test/testsetuserstatusdialog.cpp b/test/testsetuserstatusdialog.cpp
new file mode 100644
index 000000000..045463856
--- /dev/null
+++ b/test/testsetuserstatusdialog.cpp
@@ -0,0 +1,747 @@
+/*
+ * Copyright (C) by Felix Weilbach <felix.weilbach@nextcloud.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "userstatusconnector.h"
+#include "userstatusselectormodel.h"
+
+#include <QTest>
+#include <QSignalSpy>
+#include <QDateTime>
+
+#include <memory>
+
+class FakeUserStatusConnector : public OCC::UserStatusConnector
+{
+public:
+ void fetchUserStatus() override
+ {
+ if (_couldNotFetchUserStatus) {
+ emit error(Error::CouldNotFetchUserStatus);
+ return;
+ } else if (_userStatusNotSupported) {
+ emit error(Error::UserStatusNotSupported);
+ return;
+ } else if (_emojisNotSupported) {
+ emit error(Error::EmojisNotSupported);
+ return;
+ }
+
+ emit userStatusFetched(_userStatus);
+ }
+
+ void fetchPredefinedStatuses() override
+ {
+ if (_couldNotFetchPredefinedUserStatuses) {
+ emit error(Error::CouldNotFetchPredefinedUserStatuses);
+ return;
+ }
+ emit predefinedStatusesFetched(_predefinedStatuses);
+ }
+
+ void setUserStatus(const OCC::UserStatus &userStatus) override
+ {
+ if (_couldNotSetUserStatusMessage) {
+ emit error(Error::CouldNotSetUserStatus);
+ return;
+ }
+
+ _userStatusSetByCallerOfSetUserStatus = userStatus;
+ emit UserStatusConnector::userStatusSet();
+ }
+
+ void clearMessage() override
+ {
+ if (_couldNotClearUserStatusMessage) {
+ emit error(Error::CouldNotClearMessage);
+ } else {
+ _isMessageCleared = true;
+ }
+ }
+
+ OCC::UserStatus userStatus() const override
+ {
+ return {}; // Not implemented
+ }
+
+ void setFakeUserStatus(const OCC::UserStatus &userStatus)
+ {
+ _userStatus = userStatus;
+ }
+
+ void setFakePredefinedStatuses(
+ const std::vector<OCC::UserStatus> &statuses)
+ {
+ _predefinedStatuses = statuses;
+ }
+
+ OCC::UserStatus userStatusSetByCallerOfSetUserStatus() const { return _userStatusSetByCallerOfSetUserStatus; }
+
+ bool messageCleared() const { return _isMessageCleared; }
+
+ void setErrorCouldNotFetchPredefinedUserStatuses(bool value)
+ {
+ _couldNotFetchPredefinedUserStatuses = value;
+ }
+
+ void setErrorCouldNotFetchUserStatus(bool value)
+ {
+ _couldNotFetchUserStatus = value;
+ }
+
+ void setErrorCouldNotSetUserStatusMessage(bool value)
+ {
+ _couldNotSetUserStatusMessage = value;
+ }
+
+ void setErrorUserStatusNotSupported(bool value)
+ {
+ _userStatusNotSupported = value;
+ }
+
+ void setErrorEmojisNotSupported(bool value)
+ {
+ _emojisNotSupported = value;
+ }
+
+ void setErrorCouldNotClearUserStatusMessage(bool value)
+ {
+ _couldNotClearUserStatusMessage = value;
+ }
+
+private:
+ OCC::UserStatus _userStatusSetByCallerOfSetUserStatus;
+ OCC::UserStatus _userStatus;
+ std::vector<OCC::UserStatus> _predefinedStatuses;
+ bool _isMessageCleared = false;
+ bool _couldNotFetchPredefinedUserStatuses = false;
+ bool _couldNotFetchUserStatus = false;
+ bool _couldNotSetUserStatusMessage = false;
+ bool _userStatusNotSupported = false;
+ bool _emojisNotSupported = false;
+ bool _couldNotClearUserStatusMessage = false;
+};
+
+class FakeDateTimeProvider : public OCC::DateTimeProvider
+{
+public:
+ void setCurrentDateTime(const QDateTime &dateTime) { _dateTime = dateTime; }
+
+ QDateTime currentDateTime() const override { return _dateTime; }
+
+ QDate currentDate() const override { return _dateTime.date(); }
+
+private:
+ QDateTime _dateTime;
+};
+
+static std::vector<OCC::UserStatus>
+createFakePredefinedStatuses(const QDateTime &currentTime)
+{
+ std::vector<OCC::UserStatus> statuses;
+
+ const QString userStatusId("fake-id");
+ const QString userStatusMessage("Predefined status");
+ const QString userStatusIcon("🏖");
+ const OCC::UserStatus::OnlineStatus userStatusState(OCC::UserStatus::OnlineStatus::Online);
+ const bool userStatusMessagePredefined(true);
+ OCC::Optional<OCC::ClearAt> userStatusClearAt;
+ OCC::ClearAt clearAt;
+ clearAt._type = OCC::ClearAtType::Timestamp;
+ clearAt._timestamp = currentTime.addSecs(60 * 60).toTime_t();
+ userStatusClearAt = clearAt;
+
+ statuses.emplace_back(userStatusId, userStatusMessage, userStatusIcon,
+ userStatusState, userStatusMessagePredefined, userStatusClearAt);
+
+ return statuses;
+}
+
+static QDateTime createDateTime(int year = 2021, int month = 7, int day = 27,
+ int hour = 12, int minute = 0, int second = 0)
+{
+ QDate fakeDate(year, month, day);
+ QTime fakeTime(hour, minute, second);
+ QDateTime fakeDateTime;
+
+ fakeDateTime.setDate(fakeDate);
+ fakeDateTime.setTime(fakeTime);
+
+ return fakeDateTime;
+}
+
+class TestSetUserStatusDialog : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void testCtor_fetchStatusAndPredefinedStatuses()
+ {
+ const QDateTime currentDateTime(QDateTime::currentDateTime());
+
+ const QString userStatusId("fake-id");
+ const QString userStatusMessage("Some status");
+ const QString userStatusIcon("❤");
+ const OCC::UserStatus::OnlineStatus userStatusState(OCC::UserStatus::OnlineStatus::DoNotDisturb);
+ const bool userStatusMessagePredefined(false);
+ OCC::Optional<OCC::ClearAt> userStatusClearAt;
+ {
+ OCC::ClearAt clearAt;
+ clearAt._type = OCC::ClearAtType::Timestamp;
+ clearAt._timestamp = currentDateTime.addDays(1).toTime_t();
+ userStatusClearAt = clearAt;
+ }
+
+ const OCC::UserStatus userStatus(userStatusId, userStatusMessage,
+ userStatusIcon, userStatusState, userStatusMessagePredefined, userStatusClearAt);
+
+ const auto fakePredefinedStatuses = createFakePredefinedStatuses(createDateTime());
+
+ auto fakeUserStatusJob = std::make_shared<FakeUserStatusConnector>();
+ auto fakeDateTimeProvider = std::make_unique<FakeDateTimeProvider>();
+ fakeDateTimeProvider->setCurrentDateTime(currentDateTime);
+ fakeUserStatusJob->setFakeUserStatus(userStatus);
+ fakeUserStatusJob->setFakePredefinedStatuses(fakePredefinedStatuses);
+ OCC::UserStatusSelectorModel model(fakeUserStatusJob, std::move(fakeDateTimeProvider));
+
+ // Was user status set correctly?
+ QCOMPARE(model.userStatusMessage(), userStatusMessage);
+ QCOMPARE(model.userStatusEmoji(), userStatusIcon);
+ QCOMPARE(model.onlineStatus(), userStatusState);
+ QCOMPARE(model.clearAt(), tr("1 day"));
+
+ // Were predefined statuses fetched correctly?
+ const auto predefinedStatusesCount = model.predefinedStatusesCount();
+ QCOMPARE(predefinedStatusesCount, fakePredefinedStatuses.size());
+ for (int i = 0; i < predefinedStatusesCount; ++i) {
+ const auto predefinedStatus = model.predefinedStatus(i);
+ QCOMPARE(predefinedStatus.id(),
+ fakePredefinedStatuses[i].id());
+ QCOMPARE(predefinedStatus.message(),
+ fakePredefinedStatuses[i].message());
+ QCOMPARE(predefinedStatus.icon(),
+ fakePredefinedStatuses[i].icon());
+ QCOMPARE(predefinedStatus.messagePredefined(),
+ fakePredefinedStatuses[i].messagePredefined());
+ }
+ }
+
+ void testCtor_noStatusSet_showSensibleDefaults()
+ {
+ OCC::UserStatusSelectorModel model(nullptr, nullptr);
+
+ QCOMPARE(model.userStatusMessage(), "");
+ QCOMPARE(model.userStatusEmoji(), "😀");
+ QCOMPARE(model.clearAt(), tr("Don't clear"));
+ }
+
+ void testCtor_fetchStatusButNoStatusSet_showSensibleDefaults()
+ {
+ auto fakeUserStatusJob = std::make_shared<FakeUserStatusConnector>();
+ fakeUserStatusJob->setFakeUserStatus({ "", "", "",
+ OCC::UserStatus::OnlineStatus::Offline, false, {} });
+ OCC::UserStatusSelectorModel model(fakeUserStatusJob);
+
+ QCOMPARE(model.onlineStatus(), OCC::UserStatus::OnlineStatus::Online);
+ QCOMPARE(model.userStatusMessage(), "");
+ QCOMPARE(model.userStatusEmoji(), "😀");
+ QCOMPARE(model.clearAt(), tr("Don't clear"));
+ }
+
+ void testSetOnlineStatus_emitOnlineStatusChanged()
+ {
+ const OCC::UserStatus::OnlineStatus onlineStatus(OCC::UserStatus::OnlineStatus::Invisible);
+ auto fakeUserStatusJob = std::make_shared<FakeUserStatusConnector>();
+ OCC::UserStatusSelectorModel model(fakeUserStatusJob);
+ QSignalSpy onlineStatusChangedSpy(&model,
+ &OCC::UserStatusSelectorModel::onlineStatusChanged);
+
+ model.setOnlineStatus(onlineStatus);
+
+ QCOMPARE(onlineStatusChangedSpy.count(), 1);
+ }
+
+ void testSetUserStatus_setCustomMessage_userStatusSetCorrect()
+ {
+ auto fakeUserStatusJob = std::make_shared<FakeUserStatusConnector>();
+ OCC::UserStatusSelectorModel model(fakeUserStatusJob);
+ QSignalSpy finishedSpy(&model, &OCC::UserStatusSelectorModel::finished);
+
+ const QString userStatusMessage("Some status");
+ const QString userStatusIcon("❤");
+ const OCC::UserStatus::OnlineStatus userStatusState(OCC::UserStatus::OnlineStatus::Online);
+
+ model.setOnlineStatus(userStatusState);
+ model.setUserStatusMessage(userStatusMessage);
+ model.setUserStatusEmoji(userStatusIcon);
+ model.setClearAt(1);
+
+ model.setUserStatus();
+ QCOMPARE(finishedSpy.count(), 1);
+
+ const auto userStatusSet = fakeUserStatusJob->userStatusSetByCallerOfSetUserStatus();
+ QCOMPARE(userStatusSet.icon(), userStatusIcon);
+ QCOMPARE(userStatusSet.message(), userStatusMessage);
+ QCOMPARE(userStatusSet.state(), userStatusState);
+ QCOMPARE(userStatusSet.messagePredefined(), false);
+ const auto clearAt = userStatusSet.clearAt();
+ QVERIFY(clearAt.isValid());
+ QCOMPARE(clearAt->_type, OCC::ClearAtType::Period);
+ QCOMPARE(clearAt->_period, 60 * 30);
+ }
+
+ void testSetUserStatusMessage_predefinedStatusWasSet_userStatusSetCorrect()
+ {
+ auto fakeUserStatusJob = std::make_shared<FakeUserStatusConnector>();
+ fakeUserStatusJob->setFakePredefinedStatuses(createFakePredefinedStatuses(createDateTime()));
+ OCC::UserStatusSelectorModel model(fakeUserStatusJob);
+ model.setPredefinedStatus(0);
+ QSignalSpy finishedSpy(&model, &OCC::UserStatusSelectorModel::finished);
+
+ const QString userStatusMessage("Some status");
+ const OCC::UserStatus::OnlineStatus userStatusState(OCC::UserStatus::OnlineStatus::Online);
+
+ model.setOnlineStatus(userStatusState);
+ model.setUserStatusMessage(userStatusMessage);
+ model.setClearAt(1);
+
+ model.setUserStatus();
+ QCOMPARE(finishedSpy.count(), 1);
+
+ const auto userStatusSet = fakeUserStatusJob->userStatusSetByCallerOfSetUserStatus();
+ QCOMPARE(userStatusSet.message(), userStatusMessage);
+ QCOMPARE(userStatusSet.state(), userStatusState);
+ QCOMPARE(userStatusSet.messagePredefined(), false);
+ const auto clearAt = userStatusSet.clearAt();
+ QVERIFY(clearAt.isValid());
+ QCOMPARE(clearAt->_type, OCC::ClearAtType::Period);
+ QCOMPARE(clearAt->_period, 60 * 30);
+ }
+
+ void testSetUserStatusEmoji_predefinedStatusWasSet_userStatusSetCorrect()
+ {
+ auto fakeUserStatusJob = std::make_shared<FakeUserStatusConnector>();
+ fakeUserStatusJob->setFakePredefinedStatuses(createFakePredefinedStatuses(createDateTime()));
+ OCC::UserStatusSelectorModel model(fakeUserStatusJob);
+ model.setPredefinedStatus(0);
+ QSignalSpy finishedSpy(&model, &OCC::UserStatusSelectorModel::finished);
+
+ const QString userStatusIcon("❤");
+ const OCC::UserStatus::OnlineStatus userStatusState(OCC::UserStatus::OnlineStatus::Online);
+
+ model.setOnlineStatus(userStatusState);
+ model.setUserStatusEmoji(userStatusIcon);
+ model.setClearAt(1);
+
+ model.setUserStatus();
+ QCOMPARE(finishedSpy.count(), 1);
+
+ const auto userStatusSet = fakeUserStatusJob->userStatusSetByCallerOfSetUserStatus();
+ QCOMPARE(userStatusSet.icon(), userStatusIcon);
+ QCOMPARE(userStatusSet.state(), userStatusState);
+ QCOMPARE(userStatusSet.messagePredefined(), false);
+ const auto clearAt = userStatusSet.clearAt();
+ QVERIFY(clearAt.isValid());
+ QCOMPARE(clearAt->_type, OCC::ClearAtType::Period);
+ QCOMPARE(clearAt->_period, 60 * 30);
+ }
+
+ void testSetPredefinedStatus_emitUserStatusChangedAndSetUserStatus()
+ {
+ auto fakeUserStatusJob = std::make_shared<FakeUserStatusConnector>();
+ auto fakeDateTimeProvider = std::make_unique<FakeDateTimeProvider>();
+ const auto currentTime = createDateTime();
+ fakeDateTimeProvider->setCurrentDateTime(currentTime);
+ const auto fakePredefinedStatuses = createFakePredefinedStatuses(currentTime);
+ fakeUserStatusJob->setFakePredefinedStatuses(fakePredefinedStatuses);
+ OCC::UserStatusSelectorModel model(std::move(fakeUserStatusJob),
+ std::move(fakeDateTimeProvider));
+
+ QSignalSpy userStatusChangedSpy(&model,
+ &OCC::UserStatusSelectorModel::userStatusChanged);
+ QSignalSpy clearAtChangedSpy(&model,
+ &OCC::UserStatusSelectorModel::clearAtChanged);
+
+ const auto fakePredefinedUserStatusIndex = 0;
+ model.setPredefinedStatus(fakePredefinedUserStatusIndex);
+
+ QCOMPARE(userStatusChangedSpy.count(), 1);
+ QCOMPARE(clearAtChangedSpy.count(), 1);
+
+ // Was user status set correctly?
+ const auto fakePredefinedUserStatus = fakePredefinedStatuses[fakePredefinedUserStatusIndex];
+ QCOMPARE(model.userStatusMessage(), fakePredefinedUserStatus.message());
+ QCOMPARE(model.userStatusEmoji(), fakePredefinedUserStatus.icon());
+ QCOMPARE(model.onlineStatus(), fakePredefinedUserStatus.state());
+ QCOMPARE(model.clearAt(), tr("1 hour"));
+ }
+
+ void testSetClear_setClearAtStage0_emitClearAtChangedAndClearAtSet()
+ {
+ auto fakeUserStatusJob = std::make_shared<FakeUserStatusConnector>();
+ OCC::UserStatusSelectorModel model(fakeUserStatusJob);
+ QSignalSpy clearAtChangedSpy(&model, &OCC::UserStatusSelectorModel::clearAtChanged);
+
+ const auto clearAtIndex = 0;
+ model.setClearAt(clearAtIndex);
+
+ QCOMPARE(clearAtChangedSpy.count(), 1);
+ QCOMPARE(model.clearAt(), tr("Don't clear"));
+ }
+
+ void testSetClear_setClearAtStage1_emitClearAtChangedAndClearAtSet()
+ {
+ auto fakeUserStatusJob = std::make_shared<FakeUserStatusConnector>();
+ OCC::UserStatusSelectorModel model(fakeUserStatusJob);
+ QSignalSpy clearAtChangedSpy(&model, &OCC::UserStatusSelectorModel::clearAtChanged);
+
+ const auto clearAtIndex = 1;
+ model.setClearAt(clearAtIndex);
+
+ QCOMPARE(clearAtChangedSpy.count(), 1);
+ QCOMPARE(model.clearAt(), tr("30 minutes"));
+ }
+
+ void testSetClear_setClearAtStage2_emitClearAtChangedAndClearAtSet()
+ {
+ auto fakeUserStatusJob = std::make_shared<FakeUserStatusConnector>();
+ OCC::UserStatusSelectorModel model(fakeUserStatusJob);
+ QSignalSpy clearAtChangedSpy(&model, &OCC::UserStatusSelectorModel::clearAtChanged);
+
+ const auto clearAtIndex = 2;
+ model.setClearAt(clearAtIndex);
+
+ QCOMPARE(clearAtChangedSpy.count(), 1);
+ QCOMPARE(model.clearAt(), tr("1 hour"));
+ }
+
+ void testSetClear_setClearAtStage3_emitClearAtChangedAndClearAtSet()
+ {
+ auto fakeUserStatusJob = std::make_shared<FakeUserStatusConnector>();
+ OCC::UserStatusSelectorModel model(fakeUserStatusJob);
+ QSignalSpy clearAtChangedSpy(&model, &OCC::UserStatusSelectorModel::clearAtChanged);
+
+ const auto clearAtIndex = 3;
+ model.setClearAt(clearAtIndex);
+
+ QCOMPARE(clearAtChangedSpy.count(), 1);
+ QCOMPARE(model.clearAt(), tr("4 hours"));
+ }
+
+ void testSetClear_setClearAtStage4_emitClearAtChangedAndClearAtSet()
+ {
+ auto fakeUserStatusJob = std::make_shared<FakeUserStatusConnector>();
+ OCC::UserStatusSelectorModel model(fakeUserStatusJob);
+ QSignalSpy clearAtChangedSpy(&model, &OCC::UserStatusSelectorModel::clearAtChanged);
+
+ const auto clearAtIndex = 4;
+ model.setClearAt(clearAtIndex);
+
+ QCOMPARE(clearAtChangedSpy.count(), 1);
+ QCOMPARE(model.clearAt(), tr("Today"));
+ }
+
+ void testSetClear_setClearAtStage5_emitClearAtChangedAndClearAtSet()
+ {
+ auto fakeUserStatusJob = std::make_shared<FakeUserStatusConnector>();
+ OCC::UserStatusSelectorModel model(fakeUserStatusJob);
+ QSignalSpy clearAtChangedSpy(&model, &OCC::UserStatusSelectorModel::clearAtChanged);
+
+ const auto clearAtIndex = 5;
+ model.setClearAt(clearAtIndex);
+
+ QCOMPARE(clearAtChangedSpy.count(), 1);
+ QCOMPARE(model.clearAt(), tr("This week"));
+ }
+
+ void testClearAtStages()
+ {
+ auto fakeUserStatusJob = std::make_shared<FakeUserStatusConnector>();
+ OCC::UserStatusSelectorModel model(fakeUserStatusJob);
+
+ QCOMPARE(model.clearAt(), tr("Don't clear"));
+ const auto clearAtValues = model.clearAtValues();
+ QCOMPARE(clearAtValues.count(), 6);
+
+ QCOMPARE(clearAtValues[0], tr("Don't clear"));
+ QCOMPARE(clearAtValues[1], tr("30 minutes"));
+ QCOMPARE(clearAtValues[2], tr("1 hour"));
+ QCOMPARE(clearAtValues[3], tr("4 hours"));
+ QCOMPARE(clearAtValues[4], tr("Today"));
+ QCOMPARE(clearAtValues[5], tr("This week"));
+ }
+
+ void testClearAt_clearAtTimestamp()
+ {
+ const auto currentTime = createDateTime();
+ {
+ OCC::UserStatus userStatus;
+ OCC::ClearAt clearAt;
+ clearAt._type = OCC::ClearAtType::Timestamp;
+ clearAt._timestamp = currentTime.addSecs(30).toTime_t();
+ userStatus.setClearAt(clearAt);
+
+ auto fakeDateTimeProvider = std::make_unique<FakeDateTimeProvider>();
+ fakeDateTimeProvider->setCurrentDateTime(currentTime);
+
+ OCC::UserStatusSelectorModel model(userStatus, std::move(fakeDateTimeProvider));
+
+ QCOMPARE(model.clearAt(), tr("Less than a minute"));
+ }
+
+ {
+ OCC::UserStatus userStatus;
+ OCC::ClearAt clearAt;
+ clearAt._type = OCC::ClearAtType::Timestamp;
+ clearAt._timestamp = currentTime.addSecs(60).toTime_t();
+ userStatus.setClearAt(clearAt);
+
+ auto fakeDateTimeProvider = std::make_unique<FakeDateTimeProvider>();
+ fakeDateTimeProvider->setCurrentDateTime(currentTime);
+
+ OCC::UserStatusSelectorModel model(userStatus, std::move(fakeDateTimeProvider));
+
+ QCOMPARE(model.clearAt(), tr("1 minute"));
+ }
+
+ {
+ OCC::UserStatus userStatus;
+ OCC::ClearAt clearAt;
+ clearAt._type = OCC::ClearAtType::Timestamp;
+ clearAt._timestamp = currentTime.addSecs(60 * 30).toTime_t();
+ userStatus.setClearAt(clearAt);
+
+ auto fakeDateTimeProvider = std::make_unique<FakeDateTimeProvider>();
+ fakeDateTimeProvider->setCurrentDateTime(currentTime);
+
+ OCC::UserStatusSelectorModel model(userStatus, std::move(fakeDateTimeProvider));
+
+ QCOMPARE(model.clearAt(), tr("30 minutes"));
+ }
+
+ {
+ OCC::UserStatus userStatus;
+ OCC::ClearAt clearAt;
+ clearAt._type = OCC::ClearAtType::Timestamp;
+ clearAt._timestamp = currentTime.addSecs(60 * 60).toTime_t();
+ userStatus.setClearAt(clearAt);
+
+ auto fakeDateTimeProvider = std::make_unique<FakeDateTimeProvider>();
+ fakeDateTimeProvider->setCurrentDateTime(currentTime);
+
+ OCC::UserStatusSelectorModel model(userStatus, std::move(fakeDateTimeProvider));
+
+ QCOMPARE(model.clearAt(), tr("1 hour"));
+ }
+
+ {
+ OCC::UserStatus userStatus;
+ OCC::ClearAt clearAt;
+ clearAt._type = OCC::ClearAtType::Timestamp;
+ clearAt._timestamp = currentTime.addSecs(60 * 60 * 4).toTime_t();
+ userStatus.setClearAt(clearAt);
+
+ auto fakeDateTimeProvider = std::make_unique<FakeDateTimeProvider>();
+ fakeDateTimeProvider->setCurrentDateTime(currentTime);
+
+ OCC::UserStatusSelectorModel model(userStatus, std::move(fakeDateTimeProvider));
+
+ QCOMPARE(model.clearAt(), tr("4 hours"));
+ }
+
+ {
+ OCC::UserStatus userStatus;
+ OCC::ClearAt clearAt;
+ clearAt._type = OCC::ClearAtType::Timestamp;
+ clearAt._timestamp = currentTime.addDays(1).toTime_t();
+ userStatus.setClearAt(clearAt);
+
+ auto fakeDateTimeProvider = std::make_unique<FakeDateTimeProvider>();
+ fakeDateTimeProvider->setCurrentDateTime(currentTime);
+
+ OCC::UserStatusSelectorModel model(userStatus, std::move(fakeDateTimeProvider));
+
+ QCOMPARE(model.clearAt(), tr("1 day"));
+ }
+
+ {
+ OCC::UserStatus userStatus;
+ OCC::ClearAt clearAt;
+ clearAt._type = OCC::ClearAtType::Timestamp;
+ clearAt._timestamp = currentTime.addDays(7).toTime_t();
+ userStatus.setClearAt(clearAt);
+
+ auto fakeDateTimeProvider = std::make_unique<FakeDateTimeProvider>();
+ fakeDateTimeProvider->setCurrentDateTime(currentTime);
+
+ OCC::UserStatusSelectorModel model(userStatus, std::move(fakeDateTimeProvider));
+
+ QCOMPARE(model.clearAt(), tr("7 days"));
+ }
+ }
+
+ void testClearAt_clearAtEndOf()
+ {
+ {
+ OCC::UserStatus userStatus;
+ OCC::ClearAt clearAt;
+ clearAt._type = OCC::ClearAtType::EndOf;
+ clearAt._endof = "day";
+ userStatus.setClearAt(clearAt);
+
+ OCC::UserStatusSelectorModel model(userStatus);
+
+ QCOMPARE(model.clearAt(), tr("Today"));
+ }
+
+ {
+ OCC::UserStatus userStatus;
+ OCC::ClearAt clearAt;
+ clearAt._type = OCC::ClearAtType::EndOf;
+ clearAt._endof = "week";
+ userStatus.setClearAt(clearAt);
+
+ OCC::UserStatusSelectorModel model(userStatus);
+
+ QCOMPARE(model.clearAt(), tr("This week"));
+ }
+ }
+
+ void testClearAt_clearAtAfterPeriod()
+ {
+ {
+ OCC::UserStatus userStatus;
+ OCC::ClearAt clearAt;
+ clearAt._type = OCC::ClearAtType::Period;
+ clearAt._period = 60 * 30;
+ userStatus.setClearAt(clearAt);
+
+ OCC::UserStatusSelectorModel model(userStatus);
+
+ QCOMPARE(model.clearAt(), tr("30 minutes"));
+ }
+
+ {
+ OCC::UserStatus userStatus;
+ OCC::ClearAt clearAt;
+ clearAt._type = OCC::ClearAtType::Period;
+ clearAt._period = 60 * 60;
+ userStatus.setClearAt(clearAt);
+
+ OCC::UserStatusSelectorModel model(userStatus);
+
+ QCOMPARE(model.clearAt(), tr("1 hour"));
+ }
+ }
+
+ void testClearUserStatus()
+ {
+ auto fakeUserStatusJob = std::make_shared<FakeUserStatusConnector>();
+ OCC::UserStatusSelectorModel model(fakeUserStatusJob);
+
+ model.clearUserStatus();
+
+ QVERIFY(fakeUserStatusJob->messageCleared());
+ }
+
+ void testError_couldNotFetchPredefinedStatuses_emitError()
+ {
+ auto fakeUserStatusJob = std::make_shared<FakeUserStatusConnector>();
+ fakeUserStatusJob->setErrorCouldNotFetchPredefinedUserStatuses(true);
+ OCC::UserStatusSelectorModel model(fakeUserStatusJob);
+
+ QCOMPARE(model.errorMessage(),
+ tr("Could not fetch predefined statuses. Make sure you are connected to the server."));
+ }
+
+ void testError_couldNotFetchUserStatus_emitError()
+ {
+ auto fakeUserStatusJob = std::make_shared<FakeUserStatusConnector>();
+ fakeUserStatusJob->setErrorCouldNotFetchUserStatus(true);
+ OCC::UserStatusSelectorModel model(fakeUserStatusJob);
+
+ QCOMPARE(model.errorMessage(),
+ tr("Could not fetch user status. Make sure you are connected to the server."));
+ }
+
+ void testError_userStatusNotSupported_emitError()
+ {
+ auto fakeUserStatusJob = std::make_shared<FakeUserStatusConnector>();
+ fakeUserStatusJob->setErrorUserStatusNotSupported(true);
+ OCC::UserStatusSelectorModel model(fakeUserStatusJob);
+
+ QCOMPARE(model.errorMessage(),
+ tr("User status feature is not supported. You will not be able to set your user status."));
+ }
+
+ void testError_couldSetUserStatus_emitError()
+ {
+ auto fakeUserStatusJob = std::make_shared<FakeUserStatusConnector>();
+ fakeUserStatusJob->setErrorCouldNotSetUserStatusMessage(true);
+ OCC::UserStatusSelectorModel model(fakeUserStatusJob);
+ model.setUserStatus();
+
+ QCOMPARE(model.errorMessage(),
+ tr("Could not set user status. Make sure you are connected to the server."));
+ }
+
+ void testError_emojisNotSupported_emitError()
+ {
+ auto fakeUserStatusJob = std::make_shared<FakeUserStatusConnector>();
+ fakeUserStatusJob->setErrorEmojisNotSupported(true);
+ OCC::UserStatusSelectorModel model(fakeUserStatusJob);
+
+ QCOMPARE(model.errorMessage(),
+ tr("Emojis feature is not supported. Some user status functionality may not work."));
+ }
+
+ void testError_couldNotClearMessage_emitError()
+ {
+ auto fakeUserStatusJob = std::make_shared<FakeUserStatusConnector>();
+ fakeUserStatusJob->setErrorCouldNotClearUserStatusMessage(true);
+ OCC::UserStatusSelectorModel model(fakeUserStatusJob);
+ model.clearUserStatus();
+
+ QCOMPARE(model.errorMessage(),
+ tr("Could not clear user status message. Make sure you are connected to the server."));
+ }
+
+ void testError_setUserStatus_clearErrorMessage()
+ {
+ auto fakeUserStatusJob = std::make_shared<FakeUserStatusConnector>();
+ OCC::UserStatusSelectorModel model(fakeUserStatusJob);
+
+ fakeUserStatusJob->setErrorCouldNotSetUserStatusMessage(true);
+ model.setUserStatus();
+ QVERIFY(!model.errorMessage().isEmpty());
+ fakeUserStatusJob->setErrorCouldNotSetUserStatusMessage(false);
+ model.setUserStatus();
+ QVERIFY(model.errorMessage().isEmpty());
+ }
+
+ void testError_clearUserStatus_clearErrorMessage()
+ {
+ auto fakeUserStatusJob = std::make_shared<FakeUserStatusConnector>();
+ OCC::UserStatusSelectorModel model(fakeUserStatusJob);
+
+ fakeUserStatusJob->setErrorCouldNotSetUserStatusMessage(true);
+ model.setUserStatus();
+ QVERIFY(!model.errorMessage().isEmpty());
+ fakeUserStatusJob->setErrorCouldNotSetUserStatusMessage(false);
+ model.clearUserStatus();
+ QVERIFY(model.errorMessage().isEmpty());
+ }
+};
+
+QTEST_GUILESS_MAIN(TestSetUserStatusDialog)
+#include "testsetuserstatusdialog.moc"