Compare commits

...

1 Commits

Author SHA1 Message Date
Tobias Fella
050f480955 Fix emojis in a different way
Apparently the existing fix is difficult to ship for distros. This is an alternative way, that manually goes over every text and sets the font family appropriately.
Unfortunately, we need a textDocument for that, which labels don't have, meaning we have to use TextEdits instead...
2023-05-30 18:37:15 +02:00
15 changed files with 367 additions and 128 deletions

View File

@@ -44,10 +44,6 @@ if (NOT ANDROID)
include(KDEClangFormat) include(KDEClangFormat)
endif() endif()
if(NEOCHAT_FLATPAK)
include(cmake/Flatpak.cmake)
endif()
ecm_setup_version(${PROJECT_VERSION} ecm_setup_version(${PROJECT_VERSION}
VARIABLE_PREFIX NEOCHAT VARIABLE_PREFIX NEOCHAT
VERSION_HEADER ${CMAKE_CURRENT_BINARY_DIR}/neochat-version.h VERSION_HEADER ${CMAKE_CURRENT_BINARY_DIR}/neochat-version.h
@@ -75,6 +71,13 @@ set_package_properties(Qt${QT_MAJOR_VERSION}Keychain PROPERTIES
PURPOSE "Secure storage of account secrets" PURPOSE "Secure storage of account secrets"
) )
find_package(ICU 61.0 COMPONENTS uc)
set_package_properties(ICU PROPERTIES
TYPE REQUIRED
PURPOSE "Unicode library"
)
if(ANDROID) if(ANDROID)
find_package(OpenSSL) find_package(OpenSSL)
set_package_properties(OpenSSL PROPERTIES set_package_properties(OpenSSL PROPERTIES

View File

@@ -1,14 +0,0 @@
# SPDX-FileCopyrightText: 2020 Carl Schwan <carl@carlschwan.eu>
# SPDX-License-Identifier: BSD-2-Clause
include(GNUInstallDirs)
# Include FontConfig config which uses the Emoji One font from the
# KDE Flatpak SDK.
install(
FILES
${CMAKE_CURRENT_SOURCE_DIR}/cmake/Flatpak/99-noto-mono-color-emoji.conf
DESTINATION
${CMAKE_INSTALL_SYSCONFDIR}/fonts/local.conf
)

View File

@@ -1,23 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
<alias>
<family>serif</family>
<prefer>
<family>Noto Color Emoji</family>
</prefer>
</alias>
<alias>
<family>sans-serif</family>
<prefer>
<family>Noto Color Emoji</family>
</prefer>
</alias>
<alias>
<family>monospace</family>
<prefer>
<family>Noto Color Emoji</family>
</prefer>
</alias>
</fontconfig>

View File

@@ -55,6 +55,7 @@ add_library(neochat STATIC
events/joinrulesevent.cpp events/joinrulesevent.cpp
events/stickerevent.cpp events/stickerevent.cpp
models/reactionmodel.cpp models/reactionmodel.cpp
emojifixer.cpp
) )
ecm_qt_declare_logging_category(neochat ecm_qt_declare_logging_category(neochat
@@ -109,7 +110,7 @@ else()
endif() endif()
target_include_directories(neochat PRIVATE ${CMAKE_BINARY_DIR}) target_include_directories(neochat PRIVATE ${CMAKE_BINARY_DIR})
target_link_libraries(neochat PUBLIC Qt::Core Qt::Quick Qt::Qml Qt::Gui Qt::Multimedia Qt::Network Qt::QuickControls2 KF${QT_MAJOR_VERSION}::I18n KF${QT_MAJOR_VERSION}::Kirigami2 KF${QT_MAJOR_VERSION}::Notifications KF${QT_MAJOR_VERSION}::ConfigCore KF${QT_MAJOR_VERSION}::ConfigGui KF${QT_MAJOR_VERSION}::CoreAddons KF${QT_MAJOR_VERSION}::SonnetCore KF${QT_MAJOR_VERSION}::ItemModels Quotient${QUOTIENT_SUFFIX} cmark::cmark ${QTKEYCHAIN_LIBRARIES} QCoro::Core) target_link_libraries(neochat PUBLIC Qt::Core Qt::Quick Qt::Qml Qt::Gui Qt::Multimedia Qt::Network Qt::QuickControls2 KF${QT_MAJOR_VERSION}::I18n KF${QT_MAJOR_VERSION}::Kirigami2 KF${QT_MAJOR_VERSION}::Notifications KF${QT_MAJOR_VERSION}::ConfigCore KF${QT_MAJOR_VERSION}::ConfigGui KF${QT_MAJOR_VERSION}::CoreAddons KF${QT_MAJOR_VERSION}::SonnetCore KF${QT_MAJOR_VERSION}::ItemModels Quotient${QUOTIENT_SUFFIX} cmark::cmark ${QTKEYCHAIN_LIBRARIES} QCoro::Core ICU::uc)
kconfig_add_kcfg_files(neochat GENERATE_MOC neochatconfig.kcfgc) kconfig_add_kcfg_files(neochat GENERATE_MOC neochatconfig.kcfgc)
if(NEOCHAT_FLATPAK) if(NEOCHAT_FLATPAK)

View File

@@ -14,6 +14,7 @@
#include <Sonnet/BackgroundChecker> #include <Sonnet/BackgroundChecker>
#include <Sonnet/Settings> #include <Sonnet/Settings>
#include "emojifixer.h"
#include "neochatroom.h" #include "neochatroom.h"
class SyntaxHighlighter : public QSyntaxHighlighter class SyntaxHighlighter : public QSyntaxHighlighter
@@ -183,6 +184,8 @@ void ChatDocumentHandler::setDocument(QQuickTextDocument *document)
m_document->textDocument()->disconnect(this); m_document->textDocument()->disconnect(this);
} }
m_document = document; m_document = document;
static EmojiFixer emojiFixer;
emojiFixer.addTextDocument(document);
Q_EMIT documentChanged(); Q_EMIT documentChanged();
} }

72
src/emojifixer.cpp Normal file
View File

@@ -0,0 +1,72 @@
// SPDX-FileCopyrightText: Tobias Fella <tobias.fella@kde.org>
// SPDX-License-Identifier: GPL-2.0-or-later
#include <QGuiApplication>
#include <QPalette>
#include <QQuickTextDocument>
#include <QTextBoundaryFinder>
#include <QTextCharFormat>
#include <QTextCursor>
#include <KLocalizedString>
#include <unicode/uchar.h>
#include <unicode/urename.h>
#include "emojifixer.h"
bool isEmoji(const QString &text)
{
QTextBoundaryFinder finder(QTextBoundaryFinder::Grapheme, text);
int from = 0;
while (finder.toNextBoundary() != -1) {
auto to = finder.position();
if (text[from].isSpace()) {
from = to;
continue;
}
auto first = text.mid(from, to - from).toUcs4()[0];
if (!u_hasBinaryProperty(first, UCHAR_EMOJI_PRESENTATION)) {
return false;
}
from = to;
}
return true;
}
void EmojiFixer::addTextDocument(QQuickTextDocument *document)
{
if (!document) {
return;
}
fix(document->textDocument());
}
void EmojiFixer::fix(QTextDocument *document)
{
disconnect(document, nullptr, this, nullptr);
QTextCursor curs(document);
QTextCharFormat format;
auto font = QGuiApplication::font();
font.setFamily("emoji");
format.setFont(font);
QTextBoundaryFinder finder(QTextBoundaryFinder::Grapheme, document->toRawText());
int from = 0;
while (finder.toNextBoundary() != -1) {
auto to = finder.position();
auto first = document->toRawText().mid(from, to - from).toUcs4()[0];
if (u_hasBinaryProperty(first, UCHAR_EMOJI_PRESENTATION)) {
curs.setPosition(from, QTextCursor::MoveAnchor);
curs.setPosition(to, QTextCursor::KeepAnchor);
curs.setCharFormat(format);
}
from = to;
}
connect(document, &QTextDocument::contentsChanged, this, [this, document]() {
fix(document);
});
}

20
src/emojifixer.h Normal file
View File

@@ -0,0 +1,20 @@
// SPDX-FileCopyrightText: Tobias Fella <tobias.fella@kde.org>
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <QObject>
class QQuickTextDocument;
class QTextDocument;
class EmojiFixer : public QObject
{
Q_OBJECT
public:
Q_INVOKABLE void addTextDocument(QQuickTextDocument *doc);
private:
void fix(QTextDocument *doc);
};

View File

@@ -88,6 +88,7 @@
#ifdef HAVE_COLORSCHEME #ifdef HAVE_COLORSCHEME
#include "colorschemer.h" #include "colorschemer.h"
#endif #endif
#include "emojifixer.h"
#include "models/completionmodel.h" #include "models/completionmodel.h"
#include "models/statemodel.h" #include "models/statemodel.h"
#include "neochatuser.h" #include "neochatuser.h"
@@ -188,12 +189,6 @@ int main(int argc, char *argv[])
initLogging(); initLogging();
#ifdef NEOCHAT_FLATPAK
// Copy over the included FontConfig configuration to the
// app's config dir:
QFile::copy("/app/etc/fonts/conf.d/99-noto-mono-color-emoji.conf", "/var/config/fontconfig/conf.d/99-noto-mono-color-emoji.conf");
#endif
Clipboard clipboard; Clipboard clipboard;
auto config = NeoChatConfig::self(); auto config = NeoChatConfig::self();
FileTypeSingleton fileTypeSingleton; FileTypeSingleton fileTypeSingleton;
@@ -246,6 +241,7 @@ int main(int argc, char *argv[])
qmlRegisterType<StateModel>("org.kde.neochat", 1, 0, "StateModel"); qmlRegisterType<StateModel>("org.kde.neochat", 1, 0, "StateModel");
qmlRegisterType<StateFilterModel>("org.kde.neochat", 1, 0, "StateFilterModel"); qmlRegisterType<StateFilterModel>("org.kde.neochat", 1, 0, "StateFilterModel");
qmlRegisterType<SearchModel>("org.kde.neochat", 1, 0, "SearchModel"); qmlRegisterType<SearchModel>("org.kde.neochat", 1, 0, "SearchModel");
qmlRegisterSingletonInstance("org.kde.neochat", 1, 0, "EmojiFixer", new EmojiFixer);
#ifdef QUOTIENT_07 #ifdef QUOTIENT_07
qmlRegisterType<PollHandler>("org.kde.neochat", 1, 0, "PollHandler"); qmlRegisterType<PollHandler>("org.kde.neochat", 1, 0, "PollHandler");
#endif #endif

View File

@@ -165,7 +165,7 @@ ColumnLayout {
Component { Component {
id: emojiDelegate id: emojiDelegate
Kirigami.NavigationTabButton { NeoChatTabButton {
width: root.categoryIconSize width: root.categoryIconSize
height: width height: width
checked: categories.currentIndex === model.index checked: categories.currentIndex === model.index

View File

@@ -0,0 +1,92 @@
// SPDX-FileCopyrightText: 2021 Devin Lin <espidev@gmail.com>
// SPDX-FileCopyrightText: 2021 Noah Davis <noahadvs@gmail.com>
// SPDX-License-Identifier: LGPL-2.0-or-later
import QtQuick 2.15
import QtQuick.Layouts 1.15
import QtQuick.Controls 2.15 as QQC2
import QtQuick.Templates 2.15 as T
import org.kde.kirigami 2.19 as Kirigami
import org.kde.neochat 1.0
T.TabButton {
id: control
property color foregroundColor: Qt.rgba(Kirigami.Theme.textColor.r, Kirigami.Theme.textColor.g, Kirigami.Theme.textColor.b, 0.85)
property color highlightForegroundColor: Qt.rgba(Kirigami.Theme.textColor.r, Kirigami.Theme.textColor.g, Kirigami.Theme.textColor.b, 0.85)
property color highlightBarColor: Kirigami.Theme.highlightColor
property color pressedColor: Qt.rgba(highlightBarColor.r, highlightBarColor.g, highlightBarColor.b, 0.3)
property color hoverSelectColor: Qt.rgba(highlightBarColor.r, highlightBarColor.g, highlightBarColor.b, 0.2)
property color checkedBorderColor: Qt.rgba(highlightBarColor.r, highlightBarColor.g, highlightBarColor.b, 0.7)
property color pressedBorderColor: Qt.rgba(highlightBarColor.r, highlightBarColor.g, highlightBarColor.b, 0.9)
implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
implicitContentWidth + leftPadding + rightPadding)
implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
implicitContentHeight + topPadding + bottomPadding)
display: T.AbstractButton.TextUnderIcon
Kirigami.Theme.colorSet: Kirigami.Theme.Window
Kirigami.Theme.inherit: false
// not using the hover handler built into control, since it seems to misbehave and
// permanently report hovered after a touch event
HoverHandler {
id: hoverHandler
}
padding: Kirigami.Units.smallSpacing
spacing: Kirigami.Units.smallSpacing
icon.height: control.display === T.AbstractButton.TextBesideIcon ? Kirigami.Units.iconSizes.small : Kirigami.Units.iconSizes.smallMedium
icon.width: control.display === T.AbstractButton.TextBesideIcon ? Kirigami.Units.iconSizes.small : Kirigami.Units.iconSizes.smallMedium
icon.color: control.checked ? control.highlightForegroundColor : control.foregroundColor
background: Rectangle {
Kirigami.Theme.colorSet: Kirigami.Theme.Button
Kirigami.Theme.inherit: false
implicitHeight: Kirigami.Units.gridUnit * 3 + Kirigami.Units.smallSpacing * 2
color: "transparent"
Rectangle {
width: parent.width - Kirigami.Units.largeSpacing
height: parent.height - Kirigami.Units.largeSpacing
anchors.centerIn: parent
radius: Kirigami.Units.smallSpacing
color: control.down ? pressedColor : (control.checked || hoverHandler.hovered ? hoverSelectColor : "transparent")
border.color: control.checked ? checkedBorderColor : (control.down ? pressedBorderColor : color)
border.width: 1
Behavior on color { ColorAnimation { duration: Kirigami.Units.shortDuration } }
Behavior on border.color { ColorAnimation { duration: Kirigami.Units.shortDuration } }
}
}
contentItem: QQC2.Label {
id: label
Kirigami.MnemonicData.enabled: control.enabled && control.visible
Kirigami.MnemonicData.controlType: Kirigami.MnemonicData.MenuItem
Kirigami.MnemonicData.label: control.text
text: Kirigami.MnemonicData.richTextLabel
horizontalAlignment: Text.AlignHCenter
wrapMode: Text.Wrap
elide: Text.ElideMiddle
color: control.checked ? control.highlightForegroundColor : control.foregroundColor
font.bold: control.checked
font.family: "emoji"
font.pointSize: Kirigami.Theme.defaultFont.pointSize * 1.20
Behavior on color { ColorAnimation {} }
Behavior on opacity { NumberAnimation {} }
}
}

View File

@@ -6,6 +6,7 @@ import QtQuick 2.15
import QtQuick.Controls 2.15 as QQC2 import QtQuick.Controls 2.15 as QQC2
import org.kde.kirigami 2.15 as Kirigami import org.kde.kirigami 2.15 as Kirigami
import org.kde.neochat 1.0
Flow { Flow {
id: root id: root
@@ -28,15 +29,18 @@ Flow {
id: reactionRepeater id: reactionRepeater
model: root.model model: root.model
delegate: QQC2.AbstractButton { delegate: QQC2.Control {
width: Math.max(reactionTextMetrics.advanceWidth + Kirigami.Units.smallSpacing * 4, height) width: Math.max(reactionTextMetrics.advanceWidth + Kirigami.Units.smallSpacing * 4, height)
contentItem: QQC2.Label { contentItem: TextEdit {
id: reactionLabel id: reactionLabel
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
text: model.text text: model.text
readOnly: true
Component.onCompleted: EmojiFixer.addTextDocument(reactionLabel.textDocument)
color: Kirigami.Theme.textColor
selectByMouse: false
TextMetrics { TextMetrics {
id: reactionTextMetrics id: reactionTextMetrics
text: reactionLabel.text text: reactionLabel.text
@@ -56,12 +60,16 @@ Flow {
border.width: 1 border.width: 1
} }
onClicked: reactionClicked(model.reaction) MouseArea {
anchors.fill: parent
onClicked: reactionClicked(model.reaction)
hoverEnabled: true
}
hoverEnabled: true
QQC2.ToolTip.visible: hovered QQC2.ToolTip.visible: hovered
QQC2.ToolTip.text: model.toolTip QQC2.ToolTip.text: model.toolTip
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
} }
} }
} }

View File

@@ -43,9 +43,12 @@ TextEdit {
persistentSelection: true persistentSelection: true
// Work around QTBUG 93281 Component.onCompleted: {
Component.onCompleted: if (text.includes("<img")) { EmojiFixer.addTextDocument(root.textDocument)
Controller.forceRefreshTextDocument(root.textDocument, root) // Work around QTBUG 93281
if (text.includes("<img")) {
Controller.forceRefreshTextDocument(root.textDocument, root)
}
} }
text: "<style> text: "<style>

View File

@@ -13,7 +13,7 @@ import org.kde.neochat 1.0
import './' as RoomList import './' as RoomList
Kirigami.BasicListItem { Kirigami.AbstractListItem {
id: root id: root
required property int index required property int index
@@ -26,7 +26,6 @@ Kirigami.BasicListItem {
required property string subtitleText required property string subtitleText
required property string displayName required property string displayName
readonly property bool hasNotifications: notificationCount > 0 readonly property bool hasNotifications: notificationCount > 0
topPadding: Kirigami.Units.largeSpacing topPadding: Kirigami.Units.largeSpacing
@@ -35,16 +34,154 @@ Kirigami.BasicListItem {
visible: root.categoryVisible || root.filterText.length > 0 || Config.mergeRoomList visible: root.categoryVisible || root.filterText.length > 0 || Config.mergeRoomList
highlighted: ListView.view.currentIndex === index highlighted: ListView.view.currentIndex === index
focus: true focus: true
icon: undefined property bool bold: root.hasNotifications
bold: root.hasNotifications
label: root.displayName contentItem: Item {
labelItem.textFormat: Text.PlainText id: contItem
subtitle: root.subtitleText implicitWidth: layout.implicitWidth
subtitleItem {
textFormat: Text.PlainText Binding on implicitHeight {
visible: !Config.compactRoomList value: Math.max(iconItem.size, (!subtitleItem.visible && root.reserveSpaceForSubtitle ? (labelItem.implicitHeight + labelColumn.spacing + subtitleItem.implicitHeight): labelColumn.implicitHeight) )
delayed: true
}
RowLayout {
id: layout
spacing: LayoutMirroring.enabled ? root.rightPadding : root.leftPadding
anchors.left: contItem.left
anchors.leftMargin: root.leading ? root.leadingPadding : 0
anchors.right: contItem.right
anchors.rightMargin: root.trailing ? root.trailingPadding : 0
anchors.verticalCenter: parent.verticalCenter
Kirigami.Avatar {
source: root.avatar ? `image://mxc/${root.avatar}` : ""
name: root.displayName
implicitWidth: visible ? height : 0
visible: Config.showAvatarInRoomDrawer
Layout.preferredWidth: sourceSize.width
Layout.preferredHeight: sourceSize.height
sourceSize {
width: Kirigami.Units.gridUnit + Kirigami.Units.largeSpacing * 2
height: Kirigami.Units.gridUnit + Kirigami.Units.largeSpacing * 2
}
}
Kirigami.Icon {
id: iconItem
source: root.icon.name !== "" ? root.icon.name : root.icon.source
property int size: subtitleItem.visible || reserveSpaceForSubtitle ? Kirigami.Units.iconSizes.medium : Kirigami.Units.iconSizes.smallMedium
Layout.minimumHeight: size
Layout.maximumHeight: size
Layout.minimumWidth: size
Layout.maximumWidth: size
selected: (root.highlighted || root.checked || root.down)
opacity: root.fadeContent ? 0.6 : 1.0
visible: source.toString() !== ""
}
ColumnLayout {
id: labelColumn
spacing: 0
Layout.fillWidth: true
Layout.alignment: Qt.AlignVCenter
TextEdit {
id: labelItem
text: labelMetrics.elidedText
Layout.fillWidth: true
Layout.alignment: subtitleItem.visible ? Qt.AlignLeft | Qt.AlignBottom : Qt.AlignLeft | Qt.AlignVCenter
color: (root.highlighted || root.checked || root.down) ? root.activeTextColor : root.textColor
font.weight: root.bold ? Font.Bold : Font.Normal
opacity: root.fadeContent ? 0.6 : 1.0
readOnly: true
Component.onCompleted: EmojiFixer.addTextDocument(labelItem.textDocument)
TextMetrics {
id: labelMetrics
font: labelItem.font
text: root.displayName
elideWidth: labelItem.width
elide: Qt.ElideRight
}
MouseArea {
anchors.fill: parent
onClicked: RoomManager.enterRoom(root.currentRoom)
onPressAndHold: createRoomListContextMenu()
}
}
TextEdit {
id: subtitleItem
Layout.fillWidth: true
Layout.alignment: subtitleItem.visible ? Qt.AlignLeft | Qt.AlignTop : Qt.AlignLeft | Qt.AlignVCenter
color: (root.highlighted || root.checked || root.down) ? root.activeTextColor : root.textColor
//elide: Text.ElideRight
font: Kirigami.Theme.smallFont
opacity: root.fadeContent ? 0.6 : (root.bold ? 0.9 : 0.7)
text: subtitleMetrics.elidedText
textFormat: Text.PlainText
visible: !Config.compactRoomList
readOnly: true
Component.onCompleted: EmojiFixer.addTextDocument(subtitleItem.textDocument)
TextMetrics {
id: subtitleMetrics
font: subtitleItem.font
text: root.subtitleText
elideWidth: subtitleItem.width
elide: Qt.ElideRight
}
MouseArea {
anchors.fill: parent
onClicked: RoomManager.enterRoom(root.currentRoom)
onPressAndHold: createRoomListContextMenu()
}
}
}
Kirigami.Icon {
source: "notifications-disabled"
enabled: false
implicitWidth: Kirigami.Units.iconSizes.smallMedium
implicitHeight: Kirigami.Units.iconSizes.smallMedium
visible: currentRoom.pushNotificationState === PushNotificationState.Mute && !configButton.visible && !hasNotifications
Accessible.name: i18n("Muted room")
Layout.rightMargin: Kirigami.Units.smallSpacing
}
QQC2.Label {
id: notificationCountLabel
text: notificationCount
visible: hasNotifications
color: Kirigami.Theme.textColor
horizontalAlignment: Text.AlignHCenter
background: Rectangle {
visible: notificationCount > 0
Kirigami.Theme.colorSet: Kirigami.Theme.Button
color: highlightCount > 0 ? Kirigami.Theme.positiveTextColor : Kirigami.Theme.disabledTextColor
opacity: highlightCount > 0 ? 1 : 0.3
radius: height / 2
}
Layout.rightMargin: Kirigami.Units.smallSpacing
Layout.minimumHeight: Kirigami.Units.iconSizes.smallMedium
Layout.minimumWidth: Math.max(notificationCountTextMetrics.advanceWidth + Kirigami.Units.smallSpacing * 2, height)
TextMetrics {
id: notificationCountTextMetrics
text: notificationCountLabel.text
}
}
QQC2.Button {
id: configButton
visible: root.hovered && !Kirigami.Settings.isMobile && !Config.compactRoomList
text: i18n("Configure room")
display: QQC2.Button.IconOnly
icon.name: "configure"
onClicked: createRoomListContextMenu()
}
TapHandler {
acceptedButtons: Qt.RightButton
acceptedDevices: PointerDevice.Mouse
onTapped: createRoomListContextMenu()
}
}
} }
onClicked: RoomManager.enterRoom(root.currentRoom) onClicked: RoomManager.enterRoom(root.currentRoom)
@@ -53,67 +190,6 @@ Kirigami.BasicListItem {
Keys.onEnterPressed: RoomManager.enterRoom(root.currentRoom) Keys.onEnterPressed: RoomManager.enterRoom(root.currentRoom)
Keys.onReturnPressed: RoomManager.enterRoom(root.currentRoom) Keys.onReturnPressed: RoomManager.enterRoom(root.currentRoom)
TapHandler {
acceptedButtons: Qt.RightButton
acceptedDevices: PointerDevice.Mouse
onTapped: createRoomListContextMenu()
}
leading: Kirigami.Avatar {
source: root.avatar ? `image://mxc/${root.avatar}` : ""
name: root.displayName
implicitWidth: visible ? height : 0
visible: Config.showAvatarInRoomDrawer
sourceSize {
width: Kirigami.Units.gridUnit + Kirigami.Units.largeSpacing * 2
height: Kirigami.Units.gridUnit + Kirigami.Units.largeSpacing * 2
}
}
trailing: RowLayout {
Kirigami.Icon {
source: "notifications-disabled"
enabled: false
implicitWidth: Kirigami.Units.iconSizes.smallMedium
implicitHeight: Kirigami.Units.iconSizes.smallMedium
visible: currentRoom.pushNotificationState === PushNotificationState.Mute && !configButton.visible && !hasNotifications
Accessible.name: i18n("Muted room")
Layout.rightMargin: Kirigami.Units.smallSpacing
}
QQC2.Label {
id: notificationCountLabel
text: notificationCount
visible: hasNotifications
color: Kirigami.Theme.textColor
horizontalAlignment: Text.AlignHCenter
background: Rectangle {
visible: notificationCount > 0
Kirigami.Theme.colorSet: Kirigami.Theme.Button
color: highlightCount > 0 ? Kirigami.Theme.positiveTextColor : Kirigami.Theme.disabledTextColor
opacity: highlightCount > 0 ? 1 : 0.3
radius: height / 2
}
Layout.rightMargin: Kirigami.Units.smallSpacing
Layout.minimumHeight: Kirigami.Units.iconSizes.smallMedium
Layout.minimumWidth: Math.max(notificationCountTextMetrics.advanceWidth + Kirigami.Units.smallSpacing * 2, height)
TextMetrics {
id: notificationCountTextMetrics
text: notificationCountLabel.text
}
}
QQC2.Button {
id: configButton
visible: root.hovered && !Kirigami.Settings.isMobile && !Config.compactRoomList
text: i18n("Configure room")
display: QQC2.Button.IconOnly
icon.name: "configure"
onClicked: createRoomListContextMenu()
}
}
function createRoomListContextMenu() { function createRoomListContextMenu() {
const component = Qt.createComponent(Qt.resolvedUrl("./ContextMenu.qml")) const component = Qt.createComponent(Qt.resolvedUrl("./ContextMenu.qml"))
const menu = component.createObject(root, { const menu = component.createObject(root, {

View File

@@ -92,6 +92,7 @@ ColumnLayout {
cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.IBeamCursor cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.IBeamCursor
} }
background: Item {} background: Item {}
Component.onCompleted: EmojiFixer.addTextDocument(topicText.textDocument)
} }
} }

View File

@@ -124,6 +124,7 @@
<file alias="TimelineView.qml">qml/Component/TimelineView.qml</file> <file alias="TimelineView.qml">qml/Component/TimelineView.qml</file>
<file alias="InvitationView.qml">qml/Component/InvitationView.qml</file> <file alias="InvitationView.qml">qml/Component/InvitationView.qml</file>
<file alias="AvatarTabButton.qml">qml/Component/AvatarTabButton.qml</file> <file alias="AvatarTabButton.qml">qml/Component/AvatarTabButton.qml</file>
<file alias="NeoChatTabButton.qml">qml/Component/NeoChatTabButton.qml</file>
<file alias="SpaceDrawer.qml">qml/Page/RoomList/SpaceDrawer.qml</file> <file alias="SpaceDrawer.qml">qml/Page/RoomList/SpaceDrawer.qml</file>
</qresource> </qresource>
</RCC> </RCC>