feat: Add emoji support (#575)

* feat: Add emoji support
1. StatusChatListItem (only updated parts already done by Jo)
2. StatusListItem
3. StatusInput

* feat(StatusColorSelectorGrid): Added new widget for color selection as needed in wallet

* fix(StatusInput): on reset, valid should be set to true else error mode is shown even though the user hasnt entered a value

* fix(StatusLetterIdenticon): Removed the clicked event out from the LetterIdenticon and added it to the StatusBaseInput as other places that use the letterIdenticon dont need the mouse area is not needed
This commit is contained in:
Khushboo-dev-cpp 2022-03-11 20:34:21 +01:00 committed by GitHub
parent 56b2663e4d
commit 428b165198
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 239 additions and 10 deletions

View File

@ -67,7 +67,7 @@ GridLayout {
StatusChatListItem { StatusChatListItem {
name: "community-channel-emoji" name: "community-channel-emoji"
type: StatusChatListItem.Type.CommunityChat type: StatusChatListItem.Type.CommunityChat
emoji: "😁" icon.emoji: "😁"
} }
StatusChatListItem { StatusChatListItem {
@ -338,6 +338,15 @@ CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2I
} }
} }
StatusListItem {
title: "List Item with Emoji"
subTitle: "Emoji"
icon.emoji: "😁"
icon.color: "yellow"
icon.letterSize: 14
icon.isLetterIdenticon: true
}
StatusDescriptionListItem { StatusDescriptionListItem {
title: "Title" title: "Title"
subTitle: "Subtitle" subTitle: "Subtitle"

View File

@ -293,6 +293,11 @@ StatusWindow {
selected: viewLoader.source.toString().includes(title) selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title); onClicked: mainPageView.page(title);
} }
StatusNavigationListItem {
title: "StatusColorSelectorGrid"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title);
}
} }
} }
} }

View File

@ -0,0 +1,36 @@
import QtQuick 2.14
import StatusQ.Core 0.1
import StatusQ.Controls 0.1
import StatusQ.Core.Theme 0.1
Item {
id: root
width: 800
height: 100
Row {
id: selectedColor
anchors.top: parent.top
anchors.left: colorSelectionGrid.left
spacing: 10
StatusBaseText {
text: "SelectedColor is"
}
Rectangle {
width: 100
height: 20
radius: width/2
color: colorSelectionGrid.selectedColor
}
}
StatusColorSelectorGrid {
id: colorSelectionGrid
anchors.top: selectedColor.bottom
anchors.topMargin: 10
anchors.horizontalCenter: parent.horizontalCenter
titleText: "COLOR"
selectedColorIndex: 2
}
}

View File

@ -130,4 +130,27 @@ Column {
input.minimumHeight: 80 input.minimumHeight: 80
input.maximumHeight: 200 input.maximumHeight: 200
} }
StatusInput {
label: "Input with emoji icon"
input.placeholderText: "Enter Name"
input.icon.emoji: "😁"
input.icon.color: "blue"
input.isIconSelectable: true
onIconClicked: {
// launch emoji popup
}
}
StatusInput {
label: "Input with selectable icon which is not an emoji"
input.placeholderText: "Enter Name"
input.icon.emoji: ""
input.icon.name: "filled-account"
input.icon.color: "blue"
input.isIconSelectable: true
onIconClicked: {
// launch emoji popup
}
}
} }

View File

@ -97,7 +97,7 @@ Column {
chatId: model.itemId chatId: model.itemId
categoryId: model.parentItemId? model.parentItemId : "" categoryId: model.parentItemId? model.parentItemId : ""
name: model.name name: model.name
emoji: model.emoji icon.emoji: model.emoji
type: !!model.type ? model.type : StatusChatListItem.Type.CommunityChat type: !!model.type ? model.type : StatusChatListItem.Type.CommunityChat
muted: model.muted muted: model.muted
hasUnreadMessages: model.hasUnreadMessages hasUnreadMessages: model.hasUnreadMessages

View File

@ -16,7 +16,6 @@ Rectangle {
property string chatId: "" property string chatId: ""
property string categoryId: "" property string categoryId: ""
property string name: "" property string name: ""
property string emoji: ""
property alias badge: statusBadge property alias badge: statusBadge
property bool hasUnreadMessages: false property bool hasUnreadMessages: false
property int notificationsCount: 0 property int notificationsCount: 0
@ -30,6 +29,7 @@ Rectangle {
height: 24 height: 24
color: Theme.palette.miscColor5 color: Theme.palette.miscColor5
letterSize: emoji ? 14 : 15 letterSize: emoji ? 14 : 15
emoji: ""
} }
property int type: StatusChatListItem.Type.PublicChat property int type: StatusChatListItem.Type.PublicChat
property bool highlighted: false property bool highlighted: false
@ -86,7 +86,6 @@ Rectangle {
image: statusChatListItem.image image: statusChatListItem.image
icon: statusChatListItem.icon icon: statusChatListItem.icon
name: statusChatListItem.name name: statusChatListItem.name
emoji: statusChatListItem.emoji
} }
StatusIcon { StatusIcon {

View File

@ -21,7 +21,10 @@ Rectangle {
id: identiconText id: identiconText
text: { text: {
if (emoji) { if (emoji) {
return Emoji.parse(emoji) if(Utils.isHtml(emoji))
return emoji
else
return Emoji.parse(emoji)
} }
return (((statusLetterIdenticon.name.charAt(0) === "#") return (((statusLetterIdenticon.name.charAt(0) === "#")
|| (statusLetterIdenticon.name.charAt(0) === "@") ? || (statusLetterIdenticon.name.charAt(0) === "@") ?
@ -31,6 +34,9 @@ Rectangle {
font.weight: Font.Bold font.weight: Font.Bold
font.pixelSize: statusLetterIdenticon.letterSize font.pixelSize: statusLetterIdenticon.letterSize
color: Qt.rgba(255, 255, 255, 0.7) color: Qt.rgba(255, 255, 255, 0.7)
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
anchors.alignWhenCentered: false
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }

View File

@ -8,7 +8,6 @@ Loader {
property string name: "" property string name: ""
property int charCount: 1 property int charCount: 1
property string emoji: ""
property int dZ: 100 property int dZ: 100
// Badge color properties must be set if badgeItem.visible = true // Badge color properties must be set if badgeItem.visible = true
@ -85,7 +84,7 @@ Loader {
height: statusSmartIdenticon.icon.height height: statusSmartIdenticon.icon.height
color: statusSmartIdenticon.icon.color color: statusSmartIdenticon.icon.color
name: statusSmartIdenticon.name name: statusSmartIdenticon.name
emoji: statusSmartIdenticon.emoji emoji: statusSmartIdenticon.icon.emoji
letterSize: statusSmartIdenticon.icon.letterSize letterSize: statusSmartIdenticon.icon.letterSize
charCount: statusSmartIdenticon.charCount charCount: statusSmartIdenticon.charCount
} }

View File

@ -2,6 +2,7 @@ import QtQuick 2.14
import QtQuick.Controls 2.14 as QC import QtQuick.Controls 2.14 as QC
import StatusQ.Components 0.1
import StatusQ.Controls 0.1 import StatusQ.Controls 0.1
import StatusQ.Core 0.1 import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1 import StatusQ.Core.Theme 0.1
@ -49,16 +50,26 @@ Item {
property bool dirty: false property bool dirty: false
property bool pending: false property bool pending: false
property bool leftIcon: true property bool leftIcon: true
property bool isIconSelectable: false
property StatusIconSettings icon: StatusIconSettings { property StatusIconSettings icon: StatusIconSettings {
width: 24 width: 24
height: 24 height: 24
name: "" name: ""
color: Theme.palette.baseColor1 color: Theme.palette.baseColor1
emoji: ""
letterSize: 14
background: StatusIconBackgroundSettings {
width: 30
height: 30
color: Theme.palette.indirectColor1
}
} }
property Item component property Item component
signal iconClicked()
onClearableChanged: { onClearableChanged: {
if (clearable && !component) { if (clearable && !component) {
clearButtonLoader.active = true clearButtonLoader.active = true
@ -109,6 +120,29 @@ Item {
edit.forceActiveFocus() edit.forceActiveFocus()
} }
StatusSmartIdenticon {
id: emoji
anchors.left: parent.left
anchors.leftMargin: 10
anchors.verticalCenter: parent.verticalCenter
icon.width: !statusBaseInput.icon.emoji ? 20 : 30
icon.height: !statusBaseInput.icon.emoji ? 20 : 30
icon.background: statusBaseInput.icon.background
icon.color: statusBaseInput.icon.color
icon.letterSize: statusBaseInput.icon.letterSize
icon.emoji: statusBaseInput.icon.emoji
icon.name: !statusBaseInput.icon.emoji ? statusBaseInput.icon.name : ""
visible: (!!statusBaseInput.icon.emoji || !!statusBaseInput.icon.name) && statusBaseInput.isIconSelectable
MouseArea {
cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
acceptedButtons: Qt.LeftButton | Qt.RightButton
anchors.fill: parent
hoverEnabled: true
enabled: emoji.visible
onClicked: statusBaseInput.iconClicked()
}
}
StatusIcon { StatusIcon {
id: statusIcon id: statusIcon
anchors.topMargin: 10 anchors.topMargin: 10
@ -121,7 +155,7 @@ Item {
width: statusBaseInput.icon.width width: statusBaseInput.icon.width
height: statusBaseInput.icon.height height: statusBaseInput.icon.height
color: statusBaseInput.icon.color color: statusBaseInput.icon.color
visible: !!statusBaseInput.icon.name visible: !!statusBaseInput.icon.name && !statusBaseInput.isIconSelectable
} }
Flickable { Flickable {
@ -129,7 +163,7 @@ Item {
anchors.top: parent.top anchors.top: parent.top
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.left: (statusIcon.visible && statusBaseInput.leftIcon) ? anchors.left: (statusIcon.visible && statusBaseInput.leftIcon) ?
statusIcon.right : parent.left statusIcon.right : emoji.visible ? emoji.right: parent.left
anchors.right: { anchors.right: {
if (!!statusBaseInput.component) { if (!!statusBaseInput.component) {
return statusBaseInputComponentSlot.left return statusBaseInputComponentSlot.left

View File

@ -0,0 +1,32 @@
import QtQuick 2.13
import QtQuick.Controls 2.14
import StatusQ.Core.Theme 0.1
RadioButton {
id: control
property string radioButtonColor: ""
property string selectionColor: StatusColors.colors['white']
implicitWidth: 48
implicitHeight: 48
indicator: Rectangle {
implicitWidth: 48
implicitHeight: 48
radius: width/2
color: radioButtonColor
Rectangle {
width: 20
height: 20
radius: width/2
color: selectionColor
border.color: StatusColors.colors['grey3']
visible: control.checked
anchors.centerIn: parent
}
}
}

View File

@ -0,0 +1,56 @@
import QtQuick 2.13
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import "./"
Column {
id: root
property alias titleText: title.text
property alias title: title
property int selectedColorIndex: 0
property string selectedColor: ""
property var model: [StatusColors.colors['black'],
StatusColors.colors['grey'],
StatusColors.colors['blue2'],
StatusColors.colors['purple'],
StatusColors.colors['cyan'],
StatusColors.colors['violet'],
StatusColors.colors['red2'],
StatusColors.colors['yellow'],
StatusColors.colors['green2'],
StatusColors.colors['moss'],
StatusColors.colors['brown'],
StatusColors.colors['brown2']]
spacing: 16
StatusBaseText {
id: title
verticalAlignment: Text.AlignVCenter
font.pixelSize: 13
color: Theme.palette.baseColor1
}
Grid {
columns: 6
rowSpacing: 16
columnSpacing: 32
Repeater {
model: root.model
delegate: StatusColorRadioButton {
checked: index === selectedColorIndex
radioButtonColor: root.model[index] || "transparent"
onCheckedChanged: {
if(checked) {
selectedColorIndex = index
selectedColor = root.model[index]
}
}
}
}
}
}

View File

@ -40,6 +40,8 @@ Item {
property var pendingValidators: [] property var pendingValidators: []
signal iconClicked()
enum ValidationMode { enum ValidationMode {
OnlyWhenDirty, // validates input only after it has become dirty OnlyWhenDirty, // validates input only after it has become dirty
Always // validates input even before it has become dirty Always // validates input even before it has become dirty
@ -49,7 +51,7 @@ Item {
property var asyncErrors: ({}) property var asyncErrors: ({})
function reset() { function reset() {
statusBaseInput.valid = false statusBaseInput.valid = true
statusBaseInput.pristine = true statusBaseInput.pristine = true
statusBaseInput.text = "" statusBaseInput.text = ""
root.errorMessage = "" root.errorMessage = ""
@ -189,6 +191,7 @@ Item {
onTextChanged: root.validate() onTextChanged: root.validate()
Keys.forwardTo: [root] Keys.forwardTo: [root]
onIconClicked: root.iconClicked()
} }
StatusBaseText { StatusBaseText {

View File

@ -33,3 +33,4 @@ StatusSwitchTabBar 0.1 StatusSwitchTabBar.qml
StatusSelectableText 0.1 StatusSelectableText.qml StatusSelectableText 0.1 StatusSelectableText.qml
StatusWalletColorButton 0.1 StatusWalletColorButton.qml StatusWalletColorButton 0.1 StatusWalletColorButton.qml
StatusWalletColorSelect 0.1 StatusWalletColorSelect.qml StatusWalletColorSelect 0.1 StatusWalletColorSelect.qml
StatusColorSelectorGrid 0.1 StatusColorSelectorGrid.qml

View File

@ -13,5 +13,6 @@ QtObject {
property int rotation property int rotation
property bool isLetterIdenticon property bool isLetterIdenticon
property int letterSize property int letterSize
property string emoji
property StatusIconBackgroundSettings background: StatusIconBackgroundSettings {} property StatusIconBackgroundSettings background: StatusIconBackgroundSettings {}
} }

View File

@ -4,6 +4,7 @@ import QtQuick 2.13
//import shared.status 1.0 //import shared.status 1.0
import "../../../assets/twemoji/twemoji.js" as Twemoji import "../../../assets/twemoji/twemoji.js" as Twemoji
import "./emojiList.js" as EmojiJSON
QtObject { QtObject {
readonly property var size: { readonly property var size: {
@ -94,4 +95,24 @@ QtObject {
} }
return undefined return undefined
} }
function getRandomEmoji() {
var randomEmoji = EmojiJSON.emoji_json[Math.floor(Math.random() * EmojiJSON.emoji_json.length)]
const extenstionIndex = randomEmoji.unicode.lastIndexOf('.');
let iconCodePoint = randomEmoji.unicode
if (extenstionIndex > -1) {
iconCodePoint = iconCodePoint.substring(0, extenstionIndex)
}
// Split the unicode to get all the parts and then encode them from hex to utf8
const splitCodePoint = iconCodePoint.split('-')
let codePointParts = []
splitCodePoint.forEach(function (codePoint) {
codePointParts.push(`0x${codePoint}`)
})
const encodedIcon = String.fromCodePoint(...codePointParts);
return Emoji.parse(encodedIcon) + ' '
}
} }

View File

@ -70,6 +70,10 @@ QtObject {
} }
return strNumber.replace(/(\.[0-9]*[1-9])0+$|\.0*$/,'$1') return strNumber.replace(/(\.[0-9]*[1-9])0+$|\.0*$/,'$1')
} }
function isHtml(text) {
return (/<\/?[a-z][\s\S]*>/i.test(text))
}
} }