Remove ImageItem, Paintable and use unified image provider.
This commit is contained in:
parent
641c82beb7
commit
8959be2cb8
|
@ -0,0 +1,63 @@
|
||||||
|
import QtQuick 2.9
|
||||||
|
import QtQuick.Controls 2.2
|
||||||
|
import QtGraphicalEffects 1.0
|
||||||
|
|
||||||
|
Item {
|
||||||
|
property string hint: "H"
|
||||||
|
property string source: ""
|
||||||
|
readonly property url realSource: source ? "image://mxc/" + source : ""
|
||||||
|
|
||||||
|
id: root
|
||||||
|
|
||||||
|
Image {
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
id: image
|
||||||
|
visible: realSource
|
||||||
|
source: realSource
|
||||||
|
sourceSize.width: width
|
||||||
|
sourceSize.height: width
|
||||||
|
fillMode: Image.PreserveAspectCrop
|
||||||
|
layer.enabled: true
|
||||||
|
layer.effect: OpacityMask {
|
||||||
|
maskSource: Rectangle {
|
||||||
|
width: image.width
|
||||||
|
height: image.width
|
||||||
|
|
||||||
|
radius: width / 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
visible: !realSource || image.status != Image.Ready
|
||||||
|
|
||||||
|
radius: height / 2
|
||||||
|
|
||||||
|
color: stringToColor(hint)
|
||||||
|
|
||||||
|
Label {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
|
||||||
|
color: "white"
|
||||||
|
text: hint[0].toUpperCase()
|
||||||
|
font.pixelSize: root.width / 2
|
||||||
|
font.bold: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function stringToColor(str) {
|
||||||
|
var hash = 0;
|
||||||
|
for (var i = 0; i < str.length; i++) {
|
||||||
|
hash = str.charCodeAt(i) + ((hash << 5) - hash);
|
||||||
|
}
|
||||||
|
var colour = '#';
|
||||||
|
for (var j = 0; j < 3; j++) {
|
||||||
|
var value = (hash >> (j * 8)) & 0xFF;
|
||||||
|
colour += ('00' + value.toString(16)).substr(-2);
|
||||||
|
}
|
||||||
|
return colour;
|
||||||
|
}
|
||||||
|
}
|
|
@ -66,14 +66,13 @@ MouseArea {
|
||||||
}
|
}
|
||||||
|
|
||||||
onWheel: {
|
onWheel: {
|
||||||
var newPos = calculateNewPosition(flickable, wheel);
|
|
||||||
// console.warn("Delta: ", wheel.pixelDelta.y);
|
// console.warn("Delta: ", wheel.pixelDelta.y);
|
||||||
// console.warn("Old position: ", flickable.contentY);
|
// console.warn("Old position: ", flickable.contentY);
|
||||||
// console.warn("New position: ", newPos);
|
// console.warn("New position: ", newPos);
|
||||||
|
|
||||||
// Show the scrollbars
|
// Show the scrollbars
|
||||||
flickable.flick(0, 0);
|
flickable.flick(0, 0);
|
||||||
flickable.contentY = newPos;
|
flickable.contentY = calculateNewPosition(flickable, wheel);
|
||||||
cancelFlickStateTimer.start()
|
cancelFlickStateTimer.start()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,14 +43,14 @@ ColumnLayout {
|
||||||
|
|
||||||
spacing: 4
|
spacing: 4
|
||||||
|
|
||||||
ImageItem {
|
Avatar {
|
||||||
Layout.preferredWidth: 32
|
Layout.preferredWidth: 32
|
||||||
Layout.preferredHeight: 32
|
Layout.preferredHeight: 32
|
||||||
Layout.alignment: Qt.AlignTop
|
Layout.alignment: Qt.AlignTop
|
||||||
|
|
||||||
visible: avatarVisible
|
visible: avatarVisible
|
||||||
hint: author.displayName
|
hint: author.displayName
|
||||||
source: author.paintable
|
source: author.avatarUrl
|
||||||
}
|
}
|
||||||
|
|
||||||
Label {
|
Label {
|
||||||
|
|
|
@ -42,14 +42,14 @@ ColumnLayout {
|
||||||
|
|
||||||
spacing: 4
|
spacing: 4
|
||||||
|
|
||||||
ImageItem {
|
Avatar {
|
||||||
Layout.preferredWidth: 32
|
Layout.preferredWidth: 32
|
||||||
Layout.preferredHeight: 32
|
Layout.preferredHeight: 32
|
||||||
Layout.alignment: Qt.AlignTop
|
Layout.alignment: Qt.AlignTop
|
||||||
|
|
||||||
visible: avatarVisible
|
visible: avatarVisible
|
||||||
hint: author.displayName
|
hint: author.displayName
|
||||||
source: author.paintable
|
source: author.avatarUrl
|
||||||
}
|
}
|
||||||
|
|
||||||
Label {
|
Label {
|
||||||
|
@ -119,12 +119,12 @@ ColumnLayout {
|
||||||
contentItem: RowLayout {
|
contentItem: RowLayout {
|
||||||
spacing: 8
|
spacing: 8
|
||||||
|
|
||||||
ImageItem {
|
Avatar {
|
||||||
Layout.preferredWidth: 36
|
Layout.preferredWidth: 36
|
||||||
Layout.preferredHeight: 36
|
Layout.preferredHeight: 36
|
||||||
Layout.alignment: Qt.AlignTop
|
Layout.alignment: Qt.AlignTop
|
||||||
|
|
||||||
source: replyAuthor ? replyAuthor.paintable : null
|
source: replyAuthor ? replyAuthor.avatarUrl : ""
|
||||||
}
|
}
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
|
|
|
@ -6,3 +6,4 @@ ScrollHelper 2.0 ScrollHelper.qml
|
||||||
AutoListView 2.0 AutoListView.qml
|
AutoListView 2.0 AutoListView.qml
|
||||||
AutoTextField 2.0 AutoTextField.qml
|
AutoTextField 2.0 AutoTextField.qml
|
||||||
SplitView 2.0 SplitView.qml
|
SplitView 2.0 SplitView.qml
|
||||||
|
Avatar 2.0 Avatar.qml
|
||||||
|
|
|
@ -7,8 +7,6 @@ import Spectral.Component 2.0
|
||||||
|
|
||||||
import Spectral 0.1
|
import Spectral 0.1
|
||||||
|
|
||||||
import "qrc:/js/util.js" as Util
|
|
||||||
|
|
||||||
Drawer {
|
Drawer {
|
||||||
property var room
|
property var room
|
||||||
|
|
||||||
|
@ -20,13 +18,13 @@ Drawer {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
anchors.margins: 32
|
anchors.margins: 32
|
||||||
|
|
||||||
ImageItem {
|
Avatar {
|
||||||
Layout.preferredWidth: 96
|
Layout.preferredWidth: 96
|
||||||
Layout.preferredHeight: 96
|
Layout.preferredHeight: 96
|
||||||
Layout.alignment: Qt.AlignHCenter
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
|
||||||
hint: room ? room.displayName : "No name"
|
hint: room ? room.displayName : "No name"
|
||||||
source: room ? room.paintable : null
|
source: room ? room.avatarUrl : null
|
||||||
}
|
}
|
||||||
|
|
||||||
Label {
|
Label {
|
||||||
|
@ -117,11 +115,11 @@ Drawer {
|
||||||
anchors.margins: 8
|
anchors.margins: 8
|
||||||
spacing: 12
|
spacing: 12
|
||||||
|
|
||||||
ImageItem {
|
Avatar {
|
||||||
Layout.preferredWidth: height
|
Layout.preferredWidth: height
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
|
|
||||||
source: paintable
|
source: avatar
|
||||||
hint: name
|
hint: name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,9 +5,10 @@ import QtQuick.Controls.Material 2.2
|
||||||
|
|
||||||
import Spectral 0.1
|
import Spectral 0.1
|
||||||
import Spectral.Effect 2.0
|
import Spectral.Effect 2.0
|
||||||
|
import Spectral.Component 2.0
|
||||||
|
|
||||||
Control {
|
Control {
|
||||||
property alias paintable: headerImage.source
|
property alias avatar: headerImage.source
|
||||||
property alias topic: headerTopicLabel.text
|
property alias topic: headerTopicLabel.text
|
||||||
property bool atTop: false
|
property bool atTop: false
|
||||||
signal clicked()
|
signal clicked()
|
||||||
|
@ -31,13 +32,13 @@ Control {
|
||||||
|
|
||||||
spacing: 12
|
spacing: 12
|
||||||
|
|
||||||
ImageItem {
|
Avatar {
|
||||||
Layout.preferredWidth: height
|
Layout.preferredWidth: height
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
|
|
||||||
id: headerImage
|
id: headerImage
|
||||||
|
|
||||||
source: currentRoom.paintable
|
source: currentRoom.avatarUrl
|
||||||
hint: currentRoom ? currentRoom.displayName : "No name"
|
hint: currentRoom ? currentRoom.displayName : "No name"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -110,13 +110,13 @@ Rectangle {
|
||||||
contentItem: ColumnLayout {
|
contentItem: ColumnLayout {
|
||||||
spacing: 4
|
spacing: 4
|
||||||
|
|
||||||
ImageItem {
|
Avatar {
|
||||||
Layout.preferredWidth: 200
|
Layout.preferredWidth: 200
|
||||||
Layout.preferredHeight: 200
|
Layout.preferredHeight: 200
|
||||||
Layout.margins: 12
|
Layout.margins: 12
|
||||||
Layout.alignment: Qt.AlignHCenter
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
|
||||||
source: root.user ? root.user.paintable : null
|
source: root.user ? root.user.avatarUrl : null
|
||||||
hint: root.user ? root.user.displayName : "?"
|
hint: root.user ? root.user.displayName : "?"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -646,14 +646,14 @@ Rectangle {
|
||||||
background: Item {}
|
background: Item {}
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageItem {
|
Avatar {
|
||||||
Layout.preferredWidth: height
|
Layout.preferredWidth: height
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
Layout.alignment: Qt.AlignRight
|
Layout.alignment: Qt.AlignRight
|
||||||
|
|
||||||
visible: !searchField.active
|
visible: !searchField.active
|
||||||
|
|
||||||
source: root.user ? root.user.paintable : null
|
source: root.user ? root.user.avatarUrl : null
|
||||||
hint: root.user ? root.user.displayName : "?"
|
hint: root.user ? root.user.displayName : "?"
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
|
@ -765,13 +765,11 @@ Rectangle {
|
||||||
|
|
||||||
spacing: 12
|
spacing: 12
|
||||||
|
|
||||||
ImageItem {
|
Avatar {
|
||||||
id: imageItem
|
|
||||||
|
|
||||||
Layout.preferredWidth: height
|
Layout.preferredWidth: height
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
|
|
||||||
source: paintable
|
source: avatar
|
||||||
hint: name || "No Name"
|
hint: name || "No Name"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,6 @@ import Spectral.Setting 0.1
|
||||||
import SortFilterProxyModel 0.2
|
import SortFilterProxyModel 0.2
|
||||||
|
|
||||||
import "qrc:/js/md.js" as Markdown
|
import "qrc:/js/md.js" as Markdown
|
||||||
import "qrc:/js/util.js" as Util
|
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
property var currentRoom: null
|
property var currentRoom: null
|
||||||
|
@ -63,7 +62,7 @@ Item {
|
||||||
|
|
||||||
id: roomHeader
|
id: roomHeader
|
||||||
|
|
||||||
paintable: currentRoom ? currentRoom.paintable : null
|
avatar: currentRoom ? currentRoom.avatarUrl : ""
|
||||||
topic: currentRoom ? (currentRoom.topic).replace(/(\r\n\t|\n|\r\t)/gm,"") : ""
|
topic: currentRoom ? (currentRoom.topic).replace(/(\r\n\t|\n|\r\t)/gm,"") : ""
|
||||||
atTop: messageListView.atYBeginning
|
atTop: messageListView.atYBeginning
|
||||||
|
|
||||||
|
@ -295,11 +294,11 @@ Item {
|
||||||
anchors.margins: 8
|
anchors.margins: 8
|
||||||
spacing: 12
|
spacing: 12
|
||||||
|
|
||||||
ImageItem {
|
Avatar {
|
||||||
Layout.preferredWidth: height
|
Layout.preferredWidth: height
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
|
|
||||||
source: modelData.paintable
|
source: modelData.avatar
|
||||||
hint: modelData.displayName
|
hint: modelData.displayName
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -50,11 +50,11 @@ Control {
|
||||||
|
|
||||||
spacing: 8
|
spacing: 8
|
||||||
|
|
||||||
ImageItem {
|
Avatar {
|
||||||
Layout.preferredWidth: 32
|
Layout.preferredWidth: 32
|
||||||
Layout.preferredHeight: 32
|
Layout.preferredHeight: 32
|
||||||
|
|
||||||
source: replyUser ? replyUser.paintable : null
|
source: replyUser ? replyUser.avatarUrl : ""
|
||||||
hint: replyUser ? replyUser.displayName : "No name"
|
hint: replyUser ? replyUser.displayName : "No name"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,11 +125,11 @@ Control {
|
||||||
verticalAlignment: Text.AlignVCenter
|
verticalAlignment: Text.AlignVCenter
|
||||||
horizontalAlignment: Text.AlignHCenter
|
horizontalAlignment: Text.AlignHCenter
|
||||||
}
|
}
|
||||||
ImageItem {
|
Avatar {
|
||||||
width: 20
|
width: 20
|
||||||
height: 20
|
height: 20
|
||||||
visible: !isEmoji
|
visible: !isEmoji
|
||||||
source: modelData.paintable || null
|
source: modelData.avatarUrl || null
|
||||||
}
|
}
|
||||||
Label {
|
Label {
|
||||||
height: parent.height
|
height: parent.height
|
||||||
|
|
12
js/util.js
12
js/util.js
|
@ -1,12 +0,0 @@
|
||||||
.pragma library
|
|
||||||
|
|
||||||
function pushToStack(stack, page) {
|
|
||||||
if(page && stack.currentItem !== page) {
|
|
||||||
if(stack.depth === 1) {
|
|
||||||
stack.replace(page)
|
|
||||||
} else {
|
|
||||||
stack.pop(null)
|
|
||||||
stack.replace(page)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -13,8 +13,6 @@ import Spectral.Effect 2.0
|
||||||
import Spectral 0.1
|
import Spectral 0.1
|
||||||
import Spectral.Setting 0.1
|
import Spectral.Setting 0.1
|
||||||
|
|
||||||
import "qrc:/js/util.js" as Util
|
|
||||||
|
|
||||||
ApplicationWindow {
|
ApplicationWindow {
|
||||||
Material.theme: MSettings.darkTheme ? Material.Dark : Material.Light
|
Material.theme: MSettings.darkTheme ? Material.Dark : Material.Light
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,6 @@ Style=Material
|
||||||
Theme=Light
|
Theme=Light
|
||||||
Primary=#344955
|
Primary=#344955
|
||||||
Accent=#673AB7
|
Accent=#673AB7
|
||||||
;Foreground=#1D333E
|
Foreground=#1D333E
|
||||||
;Background=#161616
|
Background=#161616
|
||||||
Font/Family="Roboto,Noto Sans,Noto Color Emoji"
|
Font/Family="Roboto,Noto Sans,Noto Color Emoji"
|
||||||
|
|
2
res.qrc
2
res.qrc
|
@ -3,7 +3,6 @@
|
||||||
<file>qtquickcontrols2.conf</file>
|
<file>qtquickcontrols2.conf</file>
|
||||||
<file>qml/main.qml</file>
|
<file>qml/main.qml</file>
|
||||||
<file>js/md.js</file>
|
<file>js/md.js</file>
|
||||||
<file>js/util.js</file>
|
|
||||||
<file>imports/Spectral/Component/Emoji/EmojiPicker.qml</file>
|
<file>imports/Spectral/Component/Emoji/EmojiPicker.qml</file>
|
||||||
<file>imports/Spectral/Component/Emoji/qmldir</file>
|
<file>imports/Spectral/Component/Emoji/qmldir</file>
|
||||||
<file>imports/Spectral/Component/Timeline/DownloadableContent.qml</file>
|
<file>imports/Spectral/Component/Timeline/DownloadableContent.qml</file>
|
||||||
|
@ -47,5 +46,6 @@
|
||||||
<file>imports/Spectral/Effect/CircleMask.qml</file>
|
<file>imports/Spectral/Effect/CircleMask.qml</file>
|
||||||
<file>assets/img/roompanel-dark.svg</file>
|
<file>assets/img/roompanel-dark.svg</file>
|
||||||
<file>imports/Spectral/Component/Timeline/ImageDelegate.qml</file>
|
<file>imports/Spectral/Component/Timeline/ImageDelegate.qml</file>
|
||||||
|
<file>imports/Spectral/Component/Avatar.qml</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|
|
@ -103,12 +103,10 @@ HEADERS += \
|
||||||
src/emojimodel.h \
|
src/emojimodel.h \
|
||||||
src/spectralroom.h \
|
src/spectralroom.h \
|
||||||
src/userlistmodel.h \
|
src/userlistmodel.h \
|
||||||
src/imageitem.h \
|
|
||||||
src/accountlistmodel.h \
|
src/accountlistmodel.h \
|
||||||
src/spectraluser.h \
|
src/spectraluser.h \
|
||||||
src/notifications/manager.h \
|
src/notifications/manager.h \
|
||||||
src/utils.h \
|
src/utils.h
|
||||||
src/paintable.h
|
|
||||||
|
|
||||||
SOURCES += src/main.cpp \
|
SOURCES += src/main.cpp \
|
||||||
src/controller.cpp \
|
src/controller.cpp \
|
||||||
|
@ -118,11 +116,9 @@ SOURCES += src/main.cpp \
|
||||||
src/emojimodel.cpp \
|
src/emojimodel.cpp \
|
||||||
src/spectralroom.cpp \
|
src/spectralroom.cpp \
|
||||||
src/userlistmodel.cpp \
|
src/userlistmodel.cpp \
|
||||||
src/imageitem.cpp \
|
|
||||||
src/accountlistmodel.cpp \
|
src/accountlistmodel.cpp \
|
||||||
src/spectraluser.cpp \
|
src/spectraluser.cpp \
|
||||||
src/utils.cpp \
|
src/utils.cpp
|
||||||
src/paintable.cpp
|
|
||||||
|
|
||||||
unix:!mac {
|
unix:!mac {
|
||||||
SOURCES += src/notifications/managerlinux.cpp
|
SOURCES += src/notifications/managerlinux.cpp
|
||||||
|
|
|
@ -1,108 +0,0 @@
|
||||||
#include "imageitem.h"
|
|
||||||
|
|
||||||
#include <QApplication>
|
|
||||||
#include <QBitmap>
|
|
||||||
#include <QGraphicsOpacityEffect>
|
|
||||||
#include <QRect>
|
|
||||||
#include <QScreen>
|
|
||||||
|
|
||||||
ImageItem::ImageItem(QQuickItem *parent) : QQuickPaintedItem(parent) {}
|
|
||||||
|
|
||||||
inline static QString stringtoColor(QString string) {
|
|
||||||
int hash = 0;
|
|
||||||
for (int i = 0; i < string.length(); i++)
|
|
||||||
hash = string.at(i).unicode() + ((hash << 5) - hash);
|
|
||||||
QString colour = "#";
|
|
||||||
for (int j = 0; j < 3; j++)
|
|
||||||
colour += ("00" + QString::number((hash >> (j * 8)) & 0xFF, 16)).right(2);
|
|
||||||
return colour;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline static QImage getImageFromPaintable(QPointer<Paintable> p, int width,
|
|
||||||
int height) {
|
|
||||||
if (p.isNull()) return {};
|
|
||||||
qreal dpi = QApplication::primaryScreen()->devicePixelRatio();
|
|
||||||
QImage image(p->image(width * dpi, height * dpi));
|
|
||||||
if (image.isNull()) return {};
|
|
||||||
return image;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImageItem::paint(QPainter *painter) {
|
|
||||||
QRectF bounding_rect(boundingRect());
|
|
||||||
|
|
||||||
painter->setRenderHint(QPainter::Antialiasing, true);
|
|
||||||
|
|
||||||
QImage image(getImageFromPaintable(m_paintable, bounding_rect.width(),
|
|
||||||
bounding_rect.height()));
|
|
||||||
|
|
||||||
if (image.isNull()) {
|
|
||||||
painter->setPen(Qt::NoPen);
|
|
||||||
if (m_color.isEmpty())
|
|
||||||
painter->setBrush(QColor(stringtoColor(m_hint)));
|
|
||||||
else
|
|
||||||
painter->setBrush(QColor(m_color));
|
|
||||||
if (m_round)
|
|
||||||
painter->drawEllipse(bounding_rect);
|
|
||||||
else
|
|
||||||
painter->drawRect(bounding_rect);
|
|
||||||
painter->setPen(QPen(Qt::white, 2));
|
|
||||||
QFont font;
|
|
||||||
font.setStyleHint(QFont::SansSerif);
|
|
||||||
|
|
||||||
font.setPixelSize(int(bounding_rect.width() / 2));
|
|
||||||
font.setBold(true);
|
|
||||||
painter->setFont(font);
|
|
||||||
painter->drawText(bounding_rect, Qt::AlignCenter, m_hint.at(0).toUpper());
|
|
||||||
} else {
|
|
||||||
QImage scaled;
|
|
||||||
if (image.width() > image.height()) {
|
|
||||||
scaled = image.copy((image.width() - image.height()) / 2, 0,
|
|
||||||
image.height(), image.height());
|
|
||||||
} else {
|
|
||||||
scaled = image.copy(0, (image.height() - image.width()) / 2,
|
|
||||||
image.width(), image.width());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_round) {
|
|
||||||
QPainterPath clip;
|
|
||||||
clip.addEllipse(bounding_rect); // this is the shape we want to clip to
|
|
||||||
painter->setClipPath(clip);
|
|
||||||
}
|
|
||||||
|
|
||||||
painter->drawImage(bounding_rect, scaled);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImageItem::setPaintable(Paintable *paintable) {
|
|
||||||
if (!paintable) return;
|
|
||||||
if (!m_paintable.isNull()) m_paintable->disconnect(this);
|
|
||||||
m_paintable = paintable;
|
|
||||||
connect(m_paintable, &Paintable::paintableChanged, this,
|
|
||||||
[=] { this->update(); });
|
|
||||||
emit paintableChanged();
|
|
||||||
update();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImageItem::setHint(QString newHint) {
|
|
||||||
if (!m_hint.isNull() && m_hint != newHint) {
|
|
||||||
m_hint = newHint;
|
|
||||||
emit hintChanged();
|
|
||||||
update();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImageItem::setDefaultColor(QString color) {
|
|
||||||
if (color != m_color) {
|
|
||||||
m_color = color;
|
|
||||||
emit defaultColorChanged();
|
|
||||||
update();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImageItem::setRound(bool value) {
|
|
||||||
if (m_round != value) {
|
|
||||||
m_round = value;
|
|
||||||
emit roundChanged();
|
|
||||||
update();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,52 +0,0 @@
|
||||||
#ifndef IMAGEITEM_H
|
|
||||||
#define IMAGEITEM_H
|
|
||||||
|
|
||||||
#include <QPointer>
|
|
||||||
#include <QImage>
|
|
||||||
#include <QObject>
|
|
||||||
#include <QPainter>
|
|
||||||
#include <QQuickItem>
|
|
||||||
#include <QQuickPaintedItem>
|
|
||||||
|
|
||||||
#include "paintable.h"
|
|
||||||
|
|
||||||
class ImageItem : public QQuickPaintedItem {
|
|
||||||
Q_OBJECT
|
|
||||||
Q_PROPERTY(Paintable* source READ paintable WRITE setPaintable NOTIFY
|
|
||||||
paintableChanged)
|
|
||||||
Q_PROPERTY(QString hint READ hint WRITE setHint NOTIFY hintChanged)
|
|
||||||
Q_PROPERTY(QString defaultColor READ defaultColor WRITE setDefaultColor NOTIFY
|
|
||||||
defaultColorChanged)
|
|
||||||
Q_PROPERTY(bool round READ round WRITE setRound NOTIFY roundChanged)
|
|
||||||
|
|
||||||
public:
|
|
||||||
ImageItem(QQuickItem* parent = nullptr);
|
|
||||||
|
|
||||||
void paint(QPainter* painter);
|
|
||||||
|
|
||||||
Paintable* paintable() { return m_paintable; }
|
|
||||||
void setPaintable(Paintable* paintable);
|
|
||||||
|
|
||||||
QString hint() { return m_hint; }
|
|
||||||
void setHint(QString hint);
|
|
||||||
|
|
||||||
QString defaultColor() { return m_color; }
|
|
||||||
void setDefaultColor(QString color);
|
|
||||||
|
|
||||||
bool round() { return m_round; }
|
|
||||||
void setRound(bool value);
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void paintableChanged();
|
|
||||||
void hintChanged();
|
|
||||||
void defaultColorChanged();
|
|
||||||
void roundChanged();
|
|
||||||
|
|
||||||
private:
|
|
||||||
QPointer<Paintable> m_paintable;
|
|
||||||
QString m_hint = "H";
|
|
||||||
QString m_color;
|
|
||||||
bool m_round = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // IMAGEITEM_H
|
|
|
@ -16,11 +16,7 @@ ImageProvider::ImageProvider(QObject* parent)
|
||||||
: QObject(parent),
|
: QObject(parent),
|
||||||
QQuickImageProvider(
|
QQuickImageProvider(
|
||||||
QQmlImageProviderBase::Image,
|
QQmlImageProviderBase::Image,
|
||||||
QQmlImageProviderBase::ForceAsynchronousImageLoading) {
|
QQmlImageProviderBase::ForceAsynchronousImageLoading) {}
|
||||||
#if (QT_VERSION < QT_VERSION_CHECK(5, 10, 0))
|
|
||||||
qRegisterMetaType<MediaThumbnailJob*>();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
QImage ImageProvider::requestImage(const QString& id, QSize* pSize,
|
QImage ImageProvider::requestImage(const QString& id, QSize* pSize,
|
||||||
const QSize& requestedSize) {
|
const QSize& requestedSize) {
|
||||||
|
@ -32,31 +28,33 @@ QImage ImageProvider::requestImage(const QString& id, QSize* pSize,
|
||||||
|
|
||||||
QUrl mxcUri{id};
|
QUrl mxcUri{id};
|
||||||
|
|
||||||
|
QImage result = image(mxcUri, requestedSize);
|
||||||
|
if (!requestedSize.isEmpty() && result.size() != requestedSize) {
|
||||||
|
QImage scaled = result.scaled(requestedSize, Qt::KeepAspectRatio,
|
||||||
|
Qt::SmoothTransformation);
|
||||||
|
if (pSize != nullptr) *pSize = scaled.size();
|
||||||
|
return scaled;
|
||||||
|
}
|
||||||
|
if (pSize != nullptr) *pSize = result.size();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
QImage ImageProvider::image(const QUrl& mxc, const QSize& size) {
|
||||||
QUrl tempfilePath = QUrl::fromLocalFile(
|
QUrl tempfilePath = QUrl::fromLocalFile(
|
||||||
QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + "/" +
|
QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + "/" +
|
||||||
mxcUri.fileName() + "-" + QString::number(requestedSize.width()) + "x" +
|
mxc.fileName() + ".png");
|
||||||
QString::number(requestedSize.height()) + ".png");
|
|
||||||
|
|
||||||
QImage cachedImage;
|
QImage cachedImage;
|
||||||
if (cachedImage.load(tempfilePath.toLocalFile())) {
|
if (cachedImage.load(tempfilePath.toLocalFile())) {
|
||||||
if (pSize != nullptr) *pSize = cachedImage.size();
|
|
||||||
return cachedImage;
|
return cachedImage;
|
||||||
}
|
}
|
||||||
|
|
||||||
MediaThumbnailJob* job = nullptr;
|
MediaThumbnailJob* job = nullptr;
|
||||||
QReadLocker locker(&m_lock);
|
QReadLocker locker(&m_lock);
|
||||||
|
|
||||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
|
|
||||||
QMetaObject::invokeMethod(
|
QMetaObject::invokeMethod(
|
||||||
m_connection,
|
m_connection, [=] { return m_connection->getThumbnail(mxc, size); },
|
||||||
[=] { return m_connection->getThumbnail(mxcUri, requestedSize); },
|
|
||||||
Qt::BlockingQueuedConnection, &job);
|
Qt::BlockingQueuedConnection, &job);
|
||||||
#else
|
|
||||||
QMetaObject::invokeMethod(m_connection, "getThumbnail",
|
|
||||||
Qt::BlockingQueuedConnection,
|
|
||||||
Q_RETURN_ARG(MediaThumbnailJob*, job),
|
|
||||||
Q_ARG(QUrl, mxcUri), Q_ARG(QSize, requestedSize));
|
|
||||||
#endif
|
|
||||||
if (!job) {
|
if (!job) {
|
||||||
qDebug() << "ImageProvider: failed to send a request";
|
qDebug() << "ImageProvider: failed to send a request";
|
||||||
return {};
|
return {};
|
||||||
|
@ -71,8 +69,6 @@ QImage ImageProvider::requestImage(const QString& id, QSize* pSize,
|
||||||
condition.wait(&m_lock);
|
condition.wait(&m_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pSize != nullptr) *pSize = result.size();
|
|
||||||
|
|
||||||
result.save(tempfilePath.toLocalFile());
|
result.save(tempfilePath.toLocalFile());
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|
|
@ -33,6 +33,8 @@ class ImageProvider : public QObject, public QQuickImageProvider {
|
||||||
private:
|
private:
|
||||||
QReadWriteLock m_lock;
|
QReadWriteLock m_lock;
|
||||||
QMatrixClient::Connection* m_connection = nullptr;
|
QMatrixClient::Connection* m_connection = nullptr;
|
||||||
|
|
||||||
|
QImage image(const QUrl& mxc, const QSize& size);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // IMAGEPROVIDER_H
|
#endif // IMAGEPROVIDER_H
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
#include "accountlistmodel.h"
|
#include "accountlistmodel.h"
|
||||||
#include "controller.h"
|
#include "controller.h"
|
||||||
#include "emojimodel.h"
|
#include "emojimodel.h"
|
||||||
#include "imageitem.h"
|
|
||||||
#include "imageprovider.h"
|
#include "imageprovider.h"
|
||||||
#include "messageeventmodel.h"
|
#include "messageeventmodel.h"
|
||||||
#include "room.h"
|
#include "room.h"
|
||||||
|
@ -45,7 +44,6 @@ int main(int argc, char *argv[]) {
|
||||||
|
|
||||||
qmlRegisterType<qqsfpm::QQmlSortFilterProxyModel>("SortFilterProxyModel", 0,
|
qmlRegisterType<qqsfpm::QQmlSortFilterProxyModel>("SortFilterProxyModel", 0,
|
||||||
2, "SortFilterProxyModel");
|
2, "SortFilterProxyModel");
|
||||||
qmlRegisterType<ImageItem>("Spectral", 0, 1, "ImageItem");
|
|
||||||
qmlRegisterType<Controller>("Spectral", 0, 1, "Controller");
|
qmlRegisterType<Controller>("Spectral", 0, 1, "Controller");
|
||||||
qmlRegisterType<AccountListModel>("Spectral", 0, 1, "AccountListModel");
|
qmlRegisterType<AccountListModel>("Spectral", 0, 1, "AccountListModel");
|
||||||
qmlRegisterType<RoomListModel>("Spectral", 0, 1, "RoomListModel");
|
qmlRegisterType<RoomListModel>("Spectral", 0, 1, "RoomListModel");
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
#include "paintable.h"
|
|
||||||
|
|
||||||
Paintable::Paintable(QObject *parent) : QObject(parent) {}
|
|
|
@ -1,20 +0,0 @@
|
||||||
#ifndef PAINTABLE_H
|
|
||||||
#define PAINTABLE_H
|
|
||||||
|
|
||||||
#include <QImage>
|
|
||||||
#include <QObject>
|
|
||||||
|
|
||||||
class Paintable : public QObject {
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
Paintable(QObject* parent = nullptr);
|
|
||||||
virtual ~Paintable() = default;
|
|
||||||
|
|
||||||
virtual QImage image(int) = 0;
|
|
||||||
virtual QImage image(int, int) = 0;
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void paintableChanged();
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // PAINTABLE_H
|
|
|
@ -153,7 +153,7 @@ QVariant RoomListModel::data(const QModelIndex& index, int role) const {
|
||||||
}
|
}
|
||||||
SpectralRoom* room = m_rooms.at(index.row());
|
SpectralRoom* room = m_rooms.at(index.row());
|
||||||
if (role == NameRole) return room->displayName();
|
if (role == NameRole) return room->displayName();
|
||||||
if (role == PaintableRole) return QVariant::fromValue(room->paintable());
|
if (role == AvatarRole) return room->avatarUrl();
|
||||||
if (role == TopicRole) return room->topic();
|
if (role == TopicRole) return room->topic();
|
||||||
if (role == CategoryRole) {
|
if (role == CategoryRole) {
|
||||||
if (room->joinState() == JoinState::Invite) return RoomType::Invited;
|
if (room->joinState() == JoinState::Invite) return RoomType::Invited;
|
||||||
|
@ -193,7 +193,7 @@ void RoomListModel::unreadMessagesChanged(SpectralRoom* room) {
|
||||||
QHash<int, QByteArray> RoomListModel::roleNames() const {
|
QHash<int, QByteArray> RoomListModel::roleNames() const {
|
||||||
QHash<int, QByteArray> roles;
|
QHash<int, QByteArray> roles;
|
||||||
roles[NameRole] = "name";
|
roles[NameRole] = "name";
|
||||||
roles[PaintableRole] = "paintable";
|
roles[AvatarRole] = "avatar";
|
||||||
roles[TopicRole] = "topic";
|
roles[TopicRole] = "topic";
|
||||||
roles[CategoryRole] = "category";
|
roles[CategoryRole] = "category";
|
||||||
roles[UnreadCountRole] = "unreadCount";
|
roles[UnreadCountRole] = "unreadCount";
|
||||||
|
|
|
@ -31,7 +31,7 @@ class RoomListModel : public QAbstractListModel {
|
||||||
public:
|
public:
|
||||||
enum EventRoles {
|
enum EventRoles {
|
||||||
NameRole = Qt::UserRole + 1,
|
NameRole = Qt::UserRole + 1,
|
||||||
PaintableRole,
|
AvatarRole,
|
||||||
TopicRole,
|
TopicRole,
|
||||||
CategoryRole,
|
CategoryRole,
|
||||||
UnreadCountRole,
|
UnreadCountRole,
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
SpectralRoom::SpectralRoom(Connection* connection, QString roomId,
|
SpectralRoom::SpectralRoom(Connection* connection, QString roomId,
|
||||||
JoinState joinState)
|
JoinState joinState)
|
||||||
: Room(connection, std::move(roomId), joinState), m_paintable(this) {
|
: Room(connection, std::move(roomId), joinState) {
|
||||||
connect(this, &SpectralRoom::notificationCountChanged, this,
|
connect(this, &SpectralRoom::notificationCountChanged, this,
|
||||||
&SpectralRoom::countChanged);
|
&SpectralRoom::countChanged);
|
||||||
connect(this, &SpectralRoom::highlightCountChanged, this,
|
connect(this, &SpectralRoom::highlightCountChanged, this,
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
#ifndef SpectralRoom_H
|
#ifndef SpectralRoom_H
|
||||||
#define SpectralRoom_H
|
#define SpectralRoom_H
|
||||||
|
|
||||||
#include "paintable.h"
|
|
||||||
#include "room.h"
|
#include "room.h"
|
||||||
#include "spectraluser.h"
|
#include "spectraluser.h"
|
||||||
|
|
||||||
|
@ -11,29 +10,8 @@
|
||||||
|
|
||||||
using namespace QMatrixClient;
|
using namespace QMatrixClient;
|
||||||
|
|
||||||
class RoomPaintable : public Paintable {
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
RoomPaintable(Room* parent) : Paintable(parent), m_room(parent) {
|
|
||||||
connect(m_room, &Room::avatarChanged, [=] { emit paintableChanged(); });
|
|
||||||
}
|
|
||||||
|
|
||||||
QImage image(int dimension) override {
|
|
||||||
if (!m_room) return {};
|
|
||||||
return m_room->avatar(dimension);
|
|
||||||
}
|
|
||||||
QImage image(int width, int height) override {
|
|
||||||
if (!m_room) return {};
|
|
||||||
return m_room->avatar(width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
Room* m_room;
|
|
||||||
};
|
|
||||||
|
|
||||||
class SpectralRoom : public Room {
|
class SpectralRoom : public Room {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
Q_PROPERTY(Paintable* paintable READ paintable CONSTANT)
|
|
||||||
Q_PROPERTY(bool hasUsersTyping READ hasUsersTyping NOTIFY typingChanged)
|
Q_PROPERTY(bool hasUsersTyping READ hasUsersTyping NOTIFY typingChanged)
|
||||||
Q_PROPERTY(QString usersTyping READ getUsersTyping NOTIFY typingChanged)
|
Q_PROPERTY(QString usersTyping READ getUsersTyping NOTIFY typingChanged)
|
||||||
Q_PROPERTY(QString cachedInput READ cachedInput WRITE setCachedInput NOTIFY
|
Q_PROPERTY(QString cachedInput READ cachedInput WRITE setCachedInput NOTIFY
|
||||||
|
@ -48,8 +26,6 @@ class SpectralRoom : public Room {
|
||||||
explicit SpectralRoom(Connection* connection, QString roomId,
|
explicit SpectralRoom(Connection* connection, QString roomId,
|
||||||
JoinState joinState = {});
|
JoinState joinState = {});
|
||||||
|
|
||||||
Paintable* paintable() { return &m_paintable; }
|
|
||||||
|
|
||||||
const QString& cachedInput() const { return m_cachedInput; }
|
const QString& cachedInput() const { return m_cachedInput; }
|
||||||
void setCachedInput(const QString& input) {
|
void setCachedInput(const QString& input) {
|
||||||
if (input != m_cachedInput) {
|
if (input != m_cachedInput) {
|
||||||
|
@ -132,9 +108,6 @@ class SpectralRoom : public Room {
|
||||||
void sendTypingNotification(bool isTyping);
|
void sendTypingNotification(bool isTyping);
|
||||||
void sendReply(QString userId, QString eventId, QString replyContent,
|
void sendReply(QString userId, QString eventId, QString replyContent,
|
||||||
QString sendContent);
|
QString sendContent);
|
||||||
|
|
||||||
private:
|
|
||||||
RoomPaintable m_paintable;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SpectralRoom_H
|
#endif // SpectralRoom_H
|
||||||
|
|
|
@ -1,44 +1,18 @@
|
||||||
#ifndef SpectralUser_H
|
#ifndef SpectralUser_H
|
||||||
#define SpectralUser_H
|
#define SpectralUser_H
|
||||||
|
|
||||||
#include "paintable.h"
|
|
||||||
#include "room.h"
|
#include "room.h"
|
||||||
#include "user.h"
|
#include "user.h"
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QPointer>
|
|
||||||
|
|
||||||
using namespace QMatrixClient;
|
using namespace QMatrixClient;
|
||||||
|
|
||||||
class UserPaintable : public Paintable {
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
UserPaintable(User* parent) : Paintable(parent), m_user(parent) {}
|
|
||||||
|
|
||||||
QImage image(int dimension) override {
|
|
||||||
if (!m_user) return {};
|
|
||||||
return m_user->avatar(dimension);
|
|
||||||
}
|
|
||||||
QImage image(int width, int height) override {
|
|
||||||
if (!m_user) return {};
|
|
||||||
return m_user->avatar(width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
User* m_user;
|
|
||||||
};
|
|
||||||
|
|
||||||
class SpectralUser : public User {
|
class SpectralUser : public User {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
Q_PROPERTY(Paintable* paintable READ paintable CONSTANT)
|
|
||||||
public:
|
public:
|
||||||
SpectralUser(QString userId, Connection* connection)
|
SpectralUser(QString userId, Connection* connection)
|
||||||
: User(userId, connection), m_paintable(this) {}
|
: User(userId, connection) {}
|
||||||
|
|
||||||
Paintable* paintable() { return &m_paintable; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
UserPaintable m_paintable;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SpectralUser_H
|
#endif // SpectralUser_H
|
||||||
|
|
|
@ -72,8 +72,8 @@ QVariant UserListModel::data(const QModelIndex& index, int role) const {
|
||||||
if (role == UserIDRole) {
|
if (role == UserIDRole) {
|
||||||
return user->id();
|
return user->id();
|
||||||
}
|
}
|
||||||
if (role == PaintableRole) {
|
if (role == AvatarRole) {
|
||||||
return QVariant::fromValue((static_cast<SpectralUser*>(user))->paintable());
|
return user->avatarUrl();
|
||||||
}
|
}
|
||||||
|
|
||||||
return QVariant();
|
return QVariant();
|
||||||
|
@ -115,7 +115,7 @@ void UserListModel::refresh(QMatrixClient::User* user, QVector<int> roles) {
|
||||||
|
|
||||||
void UserListModel::avatarChanged(QMatrixClient::User* user,
|
void UserListModel::avatarChanged(QMatrixClient::User* user,
|
||||||
const QMatrixClient::Room* context) {
|
const QMatrixClient::Room* context) {
|
||||||
if (context == m_currentRoom) refresh(user, {PaintableRole});
|
if (context == m_currentRoom) refresh(user, {AvatarRole});
|
||||||
}
|
}
|
||||||
|
|
||||||
int UserListModel::findUserPos(User* user) const {
|
int UserListModel::findUserPos(User* user) const {
|
||||||
|
@ -130,6 +130,6 @@ QHash<int, QByteArray> UserListModel::roleNames() const {
|
||||||
QHash<int, QByteArray> roles;
|
QHash<int, QByteArray> roles;
|
||||||
roles[NameRole] = "name";
|
roles[NameRole] = "name";
|
||||||
roles[UserIDRole] = "userId";
|
roles[UserIDRole] = "userId";
|
||||||
roles[PaintableRole] = "paintable";
|
roles[AvatarRole] = "avatar";
|
||||||
return roles;
|
return roles;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ class UserListModel : public QAbstractListModel {
|
||||||
Q_PROPERTY(
|
Q_PROPERTY(
|
||||||
QMatrixClient::Room* room READ room WRITE setRoom NOTIFY roomChanged)
|
QMatrixClient::Room* room READ room WRITE setRoom NOTIFY roomChanged)
|
||||||
public:
|
public:
|
||||||
enum EventRoles { NameRole = Qt::UserRole + 1, UserIDRole, PaintableRole };
|
enum EventRoles { NameRole = Qt::UserRole + 1, UserIDRole, AvatarRole };
|
||||||
|
|
||||||
using User = QMatrixClient::User;
|
using User = QMatrixClient::User;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue