Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Network
NeoChat
Commits
b0f6d487
Commit
b0f6d487
authored
Aug 16, 2021
by
Tobias Fella
Browse files
Implement sending stickers
MSC2545 image packs are used as source. Currently, only room image pack events are supported.
parent
24644887
Pipeline
#124423
failed with stage
in 1 minute and 20 seconds
Changes
21
Pipelines
2
Hide whitespace changes
Inline
Side-by-side
imports/NeoChat/Component/ChatBox/ChatBox.qml
View file @
b0f6d487
...
...
@@ -106,6 +106,7 @@ Item {
onChosen
:
addText
(
emoji
)
}
}
Behavior
on
height
{
NumberAnimation
{
property
:
"
height
"
...
...
@@ -113,7 +114,6 @@ Item {
easing.type
:
Easing
.
OutCubic
}
}
}
Kirigami.Separator
{
...
...
imports/NeoChat/Component/Emoji/EmojiPicker.qml
View file @
b0f6d487
...
...
@@ -24,48 +24,45 @@ ColumnLayout {
spacing
:
0
ListView
{
Layout.fillWidth
:
true
Layout.preferredHeight
:
Kirigami
.
Units
.
gridUnit
*
2
+
2
// for the focus line
boundsBehavior
:
Flickable
.
DragOverBounds
clip
:
true
orientation
:
ListView
.
Horizontal
model
:
ListModel
{
ListElement
{
label
:
"
custom
"
;
category
:
"
custom
"
}
ListElement
{
label
:
"
⌛️
"
;
category
:
"
history
"
}
ListElement
{
label
:
"
😏
"
;
category
:
"
people
"
}
ListElement
{
label
:
"
🌲
"
;
category
:
"
nature
"
}
ListElement
{
label
:
"
🍛
"
;
category
:
"
food
"
}
ListElement
{
label
:
"
🚁
"
;
category
:
"
activity
"
}
ListElement
{
label
:
"
🚅
"
;
category
:
"
travel
"
}
ListElement
{
label
:
"
💡
"
;
category
:
"
objects
"
}
ListElement
{
label
:
"
🔣
"
;
category
:
"
symbols
"
}
ListElement
{
label
:
"
🏁
"
;
category
:
"
flags
"
}
}
RowLayout
{
Layout.alignment
:
Qt
.
AlignHCenter
Layout.preferredHeight
:
Kirigami
.
Units
.
gridUnit
*
2
delegate
:
ItemDelegate
{
id
:
del
ItemDelegate
{
id
:
emojis
required
property
string
label
required
property
string
category
property
bool
selected
:
true
Layout.fillHeight
:
true
contentItem
:
Kirigami.Icon
{
source
:
"
preferences-desktop-emoticons
"
width
:
parent
.
width
height
:
parent
.
height
}
onClicked
:
emojis
.
selected
=
true
width
:
contentItem
.
Layout
.
preferredWidth
height
:
Kirigami
.
Units
.
gridUnit
*
2
Rectangle
{
anchors.bottom
:
parent
.
bottom
contentItem
:
Kirigami.Heading
{
horizontalAlignment
:
Text
.
AlignHCenter
verticalAlignment
:
Text
.
AlignVCenter
level
:
del
.
label
===
"
custom
"
?
4
:
1
width
:
parent
.
width
height
:
2
Layout.preferredWidth
:
del
.
label
===
"
custom
"
?
implicitWidth
+
Kirigami
.
Units
.
largeSpacing
:
Kirigami
.
Units
.
gridUnit
*
2
visible
:
emojis
.
selected
font.family
:
del
.
label
===
"
custom
"
?
Kirigami
.
Theme
.
defaultFont
.
family
:
'
emoji
'
text
:
del
.
label
===
"
custom
"
?
i18n
(
"
Custom
"
)
:
del
.
label
color
:
Kirigami
.
Theme
.
focusColor
}
}
ItemDelegate
{
id
:
stickers
property
bool
selected
:
!
emojis
.
selected
Layout.fillHeight
:
true
contentItem
:
Kirigami.Icon
{
source
:
"
stickers
"
width
:
parent
.
width
height
:
parent
.
height
}
onClicked
:
emojis
.
selected
=
false
Rectangle
{
anchors.bottom
:
parent
.
bottom
...
...
@@ -73,12 +70,10 @@ ColumnLayout {
width
:
parent
.
width
height
:
2
visible
:
emojiCategory
===
category
visible
:
stickers
.
selected
color
:
Kirigami
.
Theme
.
focusColor
}
onClicked
:
emojiCategory
=
category
}
}
...
...
@@ -87,83 +82,162 @@ ColumnLayout {
Layout.preferredHeight
:
1
}
GridView
{
Loader
{
id
:
gridLoader
sourceComponent
:
emojis
.
selected
?
emojiComponent
:
stickerComponent
Layout.fillWidth
:
true
Layout.preferredHeight
:
Kirigami
.
Units
.
gridUnit
*
8
Layout.fillHeight
:
true
}
cellWidth
:
Kirigami
.
Units
.
gridUnit
*
2
cellHeight
:
Kirigami
.
Units
.
gridUnit
*
2
boundsBehavior
:
Flickable
.
DragOverBounds
clip
:
true
model
:
{
switch
(
emojiCategory
)
{
case
"
custom
"
:
return
_picker
.
customModel
case
"
history
"
:
return
emojiModel
.
history
case
"
people
"
:
return
emojiModel
.
people
case
"
nature
"
:
return
emojiModel
.
nature
case
"
food
"
:
return
emojiModel
.
food
case
"
activity
"
:
return
emojiModel
.
activity
case
"
travel
"
:
return
emojiModel
.
travel
case
"
objects
"
:
return
emojiModel
.
objects
case
"
symbols
"
:
return
emojiModel
.
symbols
case
"
flags
"
:
return
emojiModel
.
flags
}
return
null
}
delegate
:
ItemDelegate
{
width
:
Kirigami
.
Units
.
gridUnit
*
2
height
:
Kirigami
.
Units
.
gridUnit
*
2
Component
{
id
:
emojiComponent
contentItem
:
Kirigami.Heading
{
level
:
1
horizontalAlignment
:
Text
.
AlignHCenter
verticalAlignment
:
Text
.
AlignVCenter
font.family
:
'
emoji
'
text
:
modelData
.
isCustom
?
""
:
modelData
.
unicode
}
ColumnLayout
{
spacing
:
0
ListView
{
Layout.fillWidth
:
true
Layout.preferredHeight
:
Kirigami
.
Units
.
gridUnit
*
2
boundsBehavior
:
Flickable
.
DragOverBounds
Image
{
visible
:
modelData
.
isCustom
source
:
visible
?
modelData
.
unicode
:
""
anchors.fill
:
parent
anchors.margins
:
2
clip
:
true
sourceSize.width
:
width
sourceSize.height
:
height
orientation
:
ListView
.
Horizontal
Rectangle
{
anchors.fill
:
parent
visible
:
parent
.
status
===
Image
.
Loading
radius
:
height
/
2
gradient
:
ShimmerGradient
{
}
model
:
ListModel
{
ListElement
{
label
:
"
custom
"
;
category
:
"
custom
"
}
ListElement
{
label
:
"
⌛️
"
;
category
:
"
history
"
}
ListElement
{
label
:
"
😏
"
;
category
:
"
people
"
}
ListElement
{
label
:
"
🌲
"
;
category
:
"
nature
"
}
ListElement
{
label
:
"
🍛
"
;
category
:
"
food
"
}
ListElement
{
label
:
"
🚁
"
;
category
:
"
activity
"
}
ListElement
{
label
:
"
🚅
"
;
category
:
"
travel
"
}
ListElement
{
label
:
"
💡
"
;
category
:
"
objects
"
}
ListElement
{
label
:
"
🔣
"
;
category
:
"
symbols
"
}
ListElement
{
label
:
"
🏁
"
;
category
:
"
flags
"
}
}
delegate
:
ItemDelegate
{
id
:
del
required
property
string
label
required
property
string
category
width
:
contentItem
.
Layout
.
preferredWidth
height
:
Kirigami
.
Units
.
gridUnit
*
2
contentItem
:
Kirigami.Heading
{
horizontalAlignment
:
Text
.
AlignHCenter
verticalAlignment
:
Text
.
AlignVCenter
level
:
del
.
label
===
"
custom
"
?
4
:
1
Layout.preferredWidth
:
del
.
label
===
"
custom
"
?
implicitWidth
+
Kirigami
.
Units
.
largeSpacing
:
Kirigami
.
Units
.
gridUnit
*
2
font.family
:
del
.
label
===
"
custom
"
?
Kirigami
.
Theme
.
defaultFont
.
family
:
'
emoji
'
text
:
del
.
label
===
"
custom
"
?
i18n
(
"
Custom
"
)
:
del
.
label
}
Rectangle
{
anchors.bottom
:
parent
.
bottom
width
:
parent
.
width
height
:
2
visible
:
emojiCategory
===
category
color
:
Kirigami
.
Theme
.
focusColor
}
onClicked
:
emojiCategory
=
category
}
}
onClicked
:
{
if
(
modelData
.
isCustom
)
{
chosen
(
modelData
.
shortname
)
}
else
{
chosen
(
modelData
.
unicode
)
GridView
{
Layout.fillWidth
:
true
Layout.preferredHeight
:
Kirigami
.
Units
.
gridUnit
*
8
Layout.fillHeight
:
true
cellWidth
:
Kirigami
.
Units
.
gridUnit
*
2
cellHeight
:
Kirigami
.
Units
.
gridUnit
*
2
boundsBehavior
:
Flickable
.
DragOverBounds
clip
:
true
model
:
{
switch
(
emojiCategory
)
{
case
"
custom
"
:
return
_picker
.
customModel
case
"
history
"
:
return
emojiModel
.
history
case
"
people
"
:
return
emojiModel
.
people
case
"
nature
"
:
return
emojiModel
.
nature
case
"
food
"
:
return
emojiModel
.
food
case
"
activity
"
:
return
emojiModel
.
activity
case
"
travel
"
:
return
emojiModel
.
travel
case
"
objects
"
:
return
emojiModel
.
objects
case
"
symbols
"
:
return
emojiModel
.
symbols
case
"
flags
"
:
return
emojiModel
.
flags
}
return
null
}
emojiModel
.
emojiUsed
(
modelData
)
delegate
:
ItemDelegate
{
width
:
Kirigami
.
Units
.
gridUnit
*
2
height
:
Kirigami
.
Units
.
gridUnit
*
2
contentItem
:
Kirigami.Heading
{
level
:
1
horizontalAlignment
:
Text
.
AlignHCenter
verticalAlignment
:
Text
.
AlignVCenter
font.family
:
'
emoji
'
text
:
modelData
.
isCustom
?
""
:
modelData
.
unicode
}
Image
{
visible
:
modelData
.
isCustom
source
:
visible
?
modelData
.
unicode
:
""
anchors.fill
:
parent
anchors.margins
:
2
sourceSize.width
:
width
sourceSize.height
:
height
Rectangle
{
anchors.fill
:
parent
visible
:
parent
.
status
===
Image
.
Loading
radius
:
height
/
2
gradient
:
ShimmerGradient
{
}
}
}
onClicked
:
{
if
(
modelData
.
isCustom
)
{
chosen
(
modelData
.
shortname
)
}
else
{
chosen
(
modelData
.
unicode
)
}
emojiModel
.
emojiUsed
(
modelData
)
}
}
ScrollBar.vertical
:
ScrollBar
{}
}
}
}
ScrollBar.vertical
:
ScrollBar
{}
Component
{
id
:
stickerComponent
StickerPicker
{
}
}
}
imports/NeoChat/Component/Emoji/StickerPicker.qml
0 → 100644
View file @
b0f6d487
// SPDX-FileCopyrightText: 2021 Tobias Fella <fella@posteo.de>
// SPDX-License-Identifier: GPL-2.0-or-later
import
QtQuick
2.15
import
QtQuick
.
Controls
2.15
import
QtQuick
.
Layouts
1.15
import
org
.
kde
.
kirigami
2.15
as
Kirigami
import
org
.
kde
.
neochat
1.0
import
NeoChat
.
Component
1.0
ColumnLayout
{
id
:
stickerPicker
spacing
:
0
ListView
{
id
:
pack
property
string
selectedPack
Layout.fillWidth
:
true
Layout.preferredHeight
:
Kirigami
.
Units
.
gridUnit
*
2
boundsBehavior
:
Flickable
.
DragOverBounds
clip
:
true
orientation
:
ListView
.
Horizontal
model
:
ImagePacksModel
{
room
:
currentRoom
showStickers
:
true
showEmoticons
:
false
}
delegate
:
ItemDelegate
{
id
:
del
required
property
string
displayName
required
property
string
avatarUrl
required
property
string
id
height
:
Kirigami
.
Units
.
gridUnit
*
2
width
:
height
contentItem
:
Image
{
source
:
"
image://mxc/
"
+
del
.
avatarUrl
}
Rectangle
{
anchors.bottom
:
parent
.
bottom
width
:
parent
.
width
height
:
2
visible
:
pack
.
selectedPack
===
del
.
id
color
:
Kirigami
.
Theme
.
focusColor
}
onClicked
:
pack
.
selectedPack
=
id
}
}
GridView
{
id
:
grid
Layout.fillWidth
:
true
Layout.preferredHeight
:
Kirigami
.
Units
.
gridUnit
*
8
Layout.fillHeight
:
true
cellWidth
:
width
/
5
cellHeight
:
cellWidth
boundsBehavior
:
Flickable
.
DragOverBounds
clip
:
true
model
:
StickerModel
{
id
:
stickerModel
pack
:
pack
.
selectedPack
room
:
currentRoom
}
delegate
:
ItemDelegate
{
width
:
grid
.
cellWidth
height
:
width
Image
{
source
:
"
image://mxc:/
"
+
model
.
url
anchors.fill
:
parent
anchors.margins
:
2
sourceSize.width
:
width
sourceSize.height
:
height
Rectangle
{
anchors.fill
:
parent
visible
:
parent
.
status
===
Image
.
Loading
radius
:
height
/
2
gradient
:
ShimmerGradient
{
}
}
}
onClicked
:
stickerModel
.
postSticker
(
model
.
index
)
}
ScrollBar.vertical
:
ScrollBar
{}
}
}
imports/NeoChat/Component/Emoji/qmldir
View file @
b0f6d487
module NeoChat.Component.Emoji
EmojiPicker 1.0 EmojiPicker.qml
StickerPicker 1.0 StickerPicker.qml
imports/NeoChat/RoomSettings/Categories.qml
View file @
b0f6d487
...
...
@@ -30,6 +30,16 @@ Kirigami.CategorizedSettings {
room
:
root
.
room
}
}
},
Kirigami.SettingAction
{
text
:
i18n
(
"
Stickers
"
)
icon.name
:
"
stickers
"
page
:
Qt
.
resolvedUrl
(
"
RoomStickers.qml
"
)
initialProperties
:
{
return
{
room
:
root
.
room
}
}
}
]
}
imports/NeoChat/RoomSettings/ImagePackEditor.qml
0 → 100644
View file @
b0f6d487
// SPDX-FileCopyrightText: 2021 Tobias Fella <fella@posteo.de>
// SPDX-License-Identifier: GPL-2.0-or-later
import
QtQuick
2.15
import
QtQuick
.
Controls
2.15
import
QtQuick
.
Layouts
1.15
import
org
.
kde
.
kirigami
2.15
as
Kirigami
import
org
.
kde
.
neochat
1.0
import
NeoChat
.
Component
1.0
as
Components
import
NeoChat
.
Dialog
1.0
Kirigami.ScrollablePage
{
id
:
root
property
var
room
property
string
packId
title
:
i18nc
(
'
@title:window
'
,
'
Edit image pack
'
)
ColumnLayout
{
anchors.fill
:
parent
ScrollView
{
id
:
scroll
Layout.fillWidth
:
true
Layout.fillHeight
:
true
ListView
{
clip
:
true
model
:
StickerModel
{
id
:
stickerModel
room
:
root
.
room
pack
:
root
.
packId
}
Kirigami.PlaceholderMessage
{
anchors.centerIn
:
parent
text
:
i18n
(
"
This sticker pack is empty
"
)
visible
:
parent
.
count
===
0
}
delegate
:
Kirigami.BasicListItem
{
text
:
model
.
body
reserveSpaceForSubtitle
:
true
leading
:
Image
{
width
:
height
sourceSize.width
:
width
sourceSize.height
:
height
source
:
"
image://mxc:/
"
+
model
.
url
Rectangle
{
anchors.fill
:
parent
visible
:
parent
.
status
===
Image
.
Loading
radius
:
height
/
2
gradient
:
Components.ShimmerGradient
{
}
}
}
trailing
:
ToolButton
{
width
:
height
icon.name
:
"
delete
"
onClicked
:
stickerModel
.
removeEmoji
(
del
.
name
)
}
}
}
}
Loader
{
active
:
pageSettingStack
.
wideMode
sourceComponent
:
addEmojiComponent
Layout.fillWidth
:
true
}
}
footer
:
ToolBar
{
position
:
ToolBar
.
Footer
RowLayout
{
anchors.fill
:
parent
Item
{
Layout.fillWidth
:
Qt
.
application
.
layoutDirection
==
Qt
.
LeftToRight
}
TextField
{
id
:
stickerField
placeholderText
:
i18n
(
"
Sticker name
"
)
}
Button
{
text
:
i18n
(
"
Add Sticker…
"
)
enabled
:
stickerField
.
text
!=
""
property
var
fileDialog
:
null
onClicked
:
{
if
(
this
.
fileDialog
!=
null
)
{
return
;
}
this
.
fileDialog
=
openFileDialog
.
createObject
(
Overlay
.
overlay
)
this
.
fileDialog
.
chosen
.
connect
((
url
)
=>
{
stickerModel
.
addEmoji
(
emojiField
.
text
,
url
)
this
.
fileDialog
=
null
})
this
.
fileDialog
.
onRejected
.
connect
(()
=>
{
this
.
fileDialog
=
null
})
this
.
fileDialog
.
open
()
}
}
Item
{
Layout.fillWidth
:
Qt
.
application
.
layoutDirection
==
Qt
.
RightToLeft
}
}
}
Component
{
id
:
openFileDialog
OpenFileDialog
{
folder
:
StandardPaths
.
writableLocation
(
StandardPaths
.
PicturesLocation
)
}
}