1
0
forked from blue/squawk

experimenting with qml

This commit is contained in:
Blue 2020-08-12 19:55:01 +03:00
parent 38159eafeb
commit 4e6bd04b02
13 changed files with 176 additions and 69 deletions

View File

@ -12,6 +12,7 @@ include(GNUInstallDirs)
include_directories(.) include_directories(.)
find_package(Qt5Widgets CONFIG REQUIRED) find_package(Qt5Widgets CONFIG REQUIRED)
find_package(Qt5QuickCompiler CONFIG REQUIRED)
find_package(Qt5LinguistTools) find_package(Qt5LinguistTools)
if(NOT CMAKE_BUILD_TYPE) if(NOT CMAKE_BUILD_TYPE)

View File

@ -77,6 +77,11 @@ int main(int argc, char *argv[])
new Shared::Global(); //translates enums new Shared::Global(); //translates enums
// QtQuickControls2 Style
if (qEnvironmentVariableIsEmpty("QT_QUICK_CONTROLS_STYLE")) {
qputenv("QT_QUICK_CONTROLS_STYLE", "Material");
}
Squawk w; Squawk w;
w.show(); w.show();

79
resources/qml/feed.qml Normal file
View File

@ -0,0 +1,79 @@
import QtQuick 2.14
import QtQuick.Controls 2.14
import QtQuick.Layouts 1.14
ListView {
id: list
verticalLayoutDirection: ListView.BottomToTop
required model
delegate: RowLayout {
id: root
width: ListView.view.width
// placeholder
Item {
Layout.preferredWidth: root.layoutDirection === Qt.LeftToRight ? 5 : 10
}
// Avatar {
// id: avatar
// visible: !sentByMe
// avatarUrl: root.avatarUrl
// Layout.alignment: Qt.AlignHCenter | Qt.AlignTop
// name: root.senderName
// Layout.preferredHeight: Kirigami.Units.gridUnit * 2.2
// Layout.preferredWidth: Kirigami.Units.gridUnit * 2.2
// }
Item {
Layout.preferredWidth: content.width + 16
Layout.preferredHeight: content.height + 16
Rectangle {
id: messageBubble
anchors.fill: parent
color: "blue"
}
ColumnLayout {
id: content
spacing: 5
anchors.centerIn: parent
Label {
text: model.sender
}
Label {
text: model.text
wrapMode: Text.Wrap
Layout.maximumWidth: root.width
}
// message meta data: date, deliveryState
RowLayout {
Layout.bottomMargin: -4
Label {
id: dateLabel
text: model.date
}
// Icon {
// source: "edit-symbolic"
// visible: model.correction
// Layout.preferredHeight: 10
// Layout.preferredWidth: 10
// }
}
}
}
Item {
Layout.fillWidth: true
}
}
}

View File

@ -160,5 +160,7 @@
<file>images/fallback/light/small/favorite.svg</file> <file>images/fallback/light/small/favorite.svg</file>
<file>images/fallback/light/small/unfavorite.svg</file> <file>images/fallback/light/small/unfavorite.svg</file>
<file>images/fallback/light/small/add.svg</file> <file>images/fallback/light/small/add.svg</file>
<file>qml/feed.qml</file>
</qresource> </qresource>
</RCC> </RCC>

View File

@ -7,8 +7,7 @@ set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON) set(CMAKE_AUTOUIC ON)
# Find the QtWidgets library # Find the QtWidgets library
find_package(Qt5Widgets CONFIG REQUIRED) find_package(Qt5 CONFIG REQUIRED COMPONENTS Widgets DBus Core)
find_package(Qt5DBus CONFIG REQUIRED)
find_package(Boost 1.36.0 CONFIG REQUIRED) find_package(Boost 1.36.0 CONFIG REQUIRED)
if(Boost_FOUND) if(Boost_FOUND)
include_directories(${Boost_INCLUDE_DIRS}) include_directories(${Boost_INCLUDE_DIRS})

View File

@ -20,6 +20,15 @@
#include <QDebug> #include <QDebug>
const QHash<int, QByteArray> MessageFeed::roles = {
{Text, "text"},
{Sender, "sender"},
{Date, "date"},
{DeliveryState, "deliveryState"},
{Correction, "correction"},
{SentByMe,"sentByMe"}
};
MessageFeed::MessageFeed(QObject* parent): MessageFeed::MessageFeed(QObject* parent):
QAbstractListModel(parent), QAbstractListModel(parent),
storage(), storage(),
@ -69,25 +78,43 @@ void MessageFeed::removeMessage(const QString& id)
QVariant MessageFeed::data(const QModelIndex& index, int role) const QVariant MessageFeed::data(const QModelIndex& index, int role) const
{ {
int i = index.row(); int i = index.row();
if (syncState == syncing) {
--i;
}
QVariant answer; QVariant answer;
switch (role) {
case Qt::DisplayRole: {
if (i == -1) {
return "Loading...";
}
StorageByTime::const_iterator itr = indexByTime.nth(i); StorageByTime::const_iterator itr = indexByTime.nth(i);
if (itr != indexByTime.end()) { if (itr != indexByTime.end()) {
const Shared::Message* msg = *itr; const Shared::Message* msg = *itr;
answer = msg->getFrom() + ": " + msg->getBody();
} switch (role) {
case Text:
answer = msg->getBody();
break;
case Sender:
answer = msg->getFrom();
break;
case Date:
answer = msg->getTime();
break;
case DeliveryState:
answer = static_cast<unsigned int>(msg->getState());
break;
case Correction:
answer = msg->getEdited();
break;
case SentByMe:
answer = msg->getOutgoing();
break;
default:
break;
}
} else {
switch (role) {
case Text:
answer = "loading...";
break;
default:
answer = "";
break;
} }
break;
default:
break;
} }
return answer; return answer;
@ -115,27 +142,28 @@ bool MessageFeed::canFetchMore(const QModelIndex& parent) const
void MessageFeed::fetchMore(const QModelIndex& parent) void MessageFeed::fetchMore(const QModelIndex& parent)
{ {
if (syncState == incomplete) { if (syncState == incomplete) {
beginInsertRows(QModelIndex(), 0, 0); beginInsertRows(QModelIndex(), storage.size(), storage.size());
syncState = syncing; syncState = syncing;
endInsertRows(); endInsertRows();
if (storage.size() == 0) { if (storage.size() == 0) {
emit requestArchive(""); emit requestArchive("");
} else { } else {
emit requestArchive((*indexByTime.nth(0))->getId()); emit requestArchive((*indexByTime.rbegin())->getId());
} }
} }
} }
void MessageFeed::responseArchive(const std::list<Shared::Message> list) void MessageFeed::responseArchive(const std::list<Shared::Message> list)
{ {
Storage::size_type size = storage.size();
if (syncState == syncing) { if (syncState == syncing) {
beginRemoveRows(QModelIndex(), 0, 0); beginRemoveRows(QModelIndex(), size, size);
syncState = incomplete; syncState = incomplete;
endRemoveRows(); endRemoveRows();
} }
beginInsertRows(QModelIndex(), 0, list.size() - 1); beginInsertRows(QModelIndex(), size, size + list.size() - 1);
for (const Shared::Message& msg : list) { for (const Shared::Message& msg : list) {
Shared::Message* copy = new Shared::Message(msg); Shared::Message* copy = new Shared::Message(msg);
storage.insert(copy); storage.insert(copy);
@ -143,3 +171,7 @@ void MessageFeed::responseArchive(const std::list<Shared::Message> list)
endInsertRows(); endInsertRows();
} }
QHash<int, QByteArray> MessageFeed::roleNames() const
{
return roles;
}

View File

@ -47,6 +47,8 @@ public:
bool canFetchMore(const QModelIndex & parent) const override; bool canFetchMore(const QModelIndex & parent) const override;
void fetchMore(const QModelIndex & parent) override; void fetchMore(const QModelIndex & parent) override;
QHash<int, QByteArray> roleNames() const override;
void responseArchive(const std::list<Shared::Message> list); void responseArchive(const std::list<Shared::Message> list);
unsigned int unreadMessagesCount() const; unsigned int unreadMessagesCount() const;
@ -54,6 +56,15 @@ public:
signals: signals:
void requestArchive(const QString& before); void requestArchive(const QString& before);
public:
enum MessageRoles {
Text = Qt::UserRole + 1,
Sender,
Date,
DeliveryState,
Correction,
SentByMe
};
private: private:
enum SyncState { enum SyncState {
incomplete, incomplete,
@ -81,7 +92,8 @@ private:
Shared::Message, Shared::Message,
QDateTime, QDateTime,
&Shared::Message::getTime &Shared::Message::getTime
> >,
std::greater<QDateTime>
> >
> >
> Storage; > Storage;
@ -94,6 +106,7 @@ private:
SyncState syncState; SyncState syncState;
static const QHash<int, QByteArray> roles;
}; };

View File

@ -7,7 +7,7 @@ set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON) set(CMAKE_AUTOUIC ON)
# Find the QtWidgets library # Find the QtWidgets library
find_package(Qt5Widgets CONFIG REQUIRED) find_package(Qt5Widgets CONFIG REQUIRED COMPONENTS Widgets Quick Qml QuickControls2 Core)
add_subdirectory(vcard) add_subdirectory(vcard)
@ -21,9 +21,12 @@ set(squawkWidgets_SRC
joinconference.cpp joinconference.cpp
) )
# Tell CMake to create the helloworld executable
add_library(squawkWidgets ${squawkWidgets_SRC}) add_library(squawkWidgets ${squawkWidgets_SRC})
# Use the Widgets module from Qt 5. # Use the Widgets module from Qt 5.
target_link_libraries(squawkWidgets vCardUI) target_link_libraries(squawkWidgets vCardUI)
target_link_libraries(squawkWidgets Qt5::Widgets) target_link_libraries(squawkWidgets Qt5::Widgets)
target_link_libraries(squawkWidgets Qt5::Qml)
target_link_libraries(squawkWidgets Qt5::QuickControls2)
qt5_use_modules(squawkWidgets Quick Qml QuickControls2 Core Widgets)

View File

@ -19,7 +19,7 @@
#include "chat.h" #include "chat.h"
Chat::Chat(Models::Account* acc, Models::Contact* p_contact, QWidget* parent): Chat::Chat(Models::Account* acc, Models::Contact* p_contact, QWidget* parent):
Conversation(false, acc, p_contact->getJid(), "", parent), Conversation(false, acc, p_contact, p_contact->getJid(), "", parent),
contact(p_contact) contact(p_contact)
{ {
setName(p_contact->getContactName()); setName(p_contact->getContactName());
@ -28,8 +28,6 @@ Chat::Chat(Models::Account* acc, Models::Contact* p_contact, QWidget* parent):
setAvatar(p_contact->getAvatarPath()); setAvatar(p_contact->getAvatarPath());
connect(contact, &Models::Contact::childChanged, this, &Chat::onContactChanged); connect(contact, &Models::Contact::childChanged, this, &Chat::onContactChanged);
feed->setModel(p_contact->feed);
} }
Chat::~Chat() Chat::~Chat()

View File

@ -29,7 +29,7 @@
#include <QAbstractTextDocumentLayout> #include <QAbstractTextDocumentLayout>
#include <QCoreApplication> #include <QCoreApplication>
Conversation::Conversation(bool muc, Models::Account* acc, const QString pJid, const QString pRes, QWidget* parent): Conversation::Conversation(bool muc, Models::Account* acc, Models::Element* el, const QString pJid, const QString pRes, QWidget* parent):
QWidget(parent), QWidget(parent),
isMuc(muc), isMuc(muc),
account(acc), account(acc),
@ -45,7 +45,7 @@ Conversation::Conversation(bool muc, Models::Account* acc, const QString pJid, c
filesLayout(0), filesLayout(0),
overlay(new QWidget()), overlay(new QWidget()),
filesToAttach(), filesToAttach(),
feed(0), feed(new QQuickView()),
scroll(down), scroll(down),
manualSliderChange(false), manualSliderChange(false),
requestingHistory(false), requestingHistory(false),
@ -53,7 +53,14 @@ Conversation::Conversation(bool muc, Models::Account* acc, const QString pJid, c
tsb(QApplication::style()->styleHint(QStyle::SH_ScrollBar_Transient) == 1) tsb(QApplication::style()->styleHint(QStyle::SH_ScrollBar_Transient) == 1)
{ {
m_ui->setupUi(this); m_ui->setupUi(this);
feed = m_ui->feed;
feed->setColor(QWidget::palette().color(QPalette::Base));
feed->setInitialProperties({{"model", QVariant::fromValue(el->feed)}});
feed->setResizeMode(QQuickView::SizeRootObjectToView);
feed->setSource(QUrl("qrc:/qml/feed.qml"));
QWidget *container = QWidget::createWindowContainer(feed, this);
container->setAutoFillBackground(false);
m_ui->widget->layout()->addWidget(container);
connect(acc, &Models::Account::childChanged, this, &Conversation::onAccountChanged); connect(acc, &Models::Account::childChanged, this, &Conversation::onAccountChanged);

View File

@ -24,7 +24,7 @@
#include <QMap> #include <QMap>
#include <QMimeData> #include <QMimeData>
#include <QFileInfo> #include <QFileInfo>
#include <QListView> #include <QQuickView>
#include "shared/message.h" #include "shared/message.h"
#include "order.h" #include "order.h"
@ -72,7 +72,7 @@ class Conversation : public QWidget
{ {
Q_OBJECT Q_OBJECT
public: public:
Conversation(bool muc, Models::Account* acc, const QString pJid, const QString pRes, QWidget* parent = 0); Conversation(bool muc, Models::Account* acc, Models::Element* el, const QString pJid, const QString pRes, QWidget* parent = 0);
~Conversation(); ~Conversation();
QString getJid() const; QString getJid() const;
@ -133,6 +133,7 @@ protected:
down down
}; };
Models::Account* account; Models::Account* account;
Models::Element* element;
QString palJid; QString palJid;
QString activePalResource; QString activePalResource;
QScopedPointer<Ui::Conversation> m_ui; QScopedPointer<Ui::Conversation> m_ui;
@ -145,7 +146,7 @@ protected:
FlowLayout* filesLayout; FlowLayout* filesLayout;
QWidget* overlay; QWidget* overlay;
W::Order<Badge*, Badge::Comparator> filesToAttach; W::Order<Badge*, Badge::Comparator> filesToAttach;
QListView* feed; QQuickView* feed;
Scroll scroll; Scroll scroll;
bool manualSliderChange; bool manualSliderChange;
bool requestingHistory; bool requestingHistory;

View File

@ -214,37 +214,6 @@
</layout> </layout>
</widget> </widget>
</item> </item>
<item>
<widget class="QListView" name="feed">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="showDropIndicator" stdset="0">
<bool>false</bool>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::NoSelection</enum>
</property>
<property name="verticalScrollMode">
<enum>QAbstractItemView::ScrollPerPixel</enum>
</property>
<property name="horizontalScrollMode">
<enum>QAbstractItemView::ScrollPerItem</enum>
</property>
<property name="isWrapping" stdset="0">
<bool>false</bool>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
</item> </item>

View File

@ -19,7 +19,7 @@
#include "room.h" #include "room.h"
Room::Room(Models::Account* acc, Models::Room* p_room, QWidget* parent): Room::Room(Models::Account* acc, Models::Room* p_room, QWidget* parent):
Conversation(true, acc, p_room->getJid(), "", parent), Conversation(true, acc, p_room, p_room->getJid(), "", parent),
room(p_room) room(p_room)
{ {
setName(p_room->getName()); setName(p_room->getName());
@ -29,8 +29,6 @@ Room::Room(Models::Account* acc, Models::Room* p_room, QWidget* parent):
connect(room, &Models::Room::childChanged, this, &Room::onRoomChanged); connect(room, &Models::Room::childChanged, this, &Room::onRoomChanged);
connect(room, &Models::Room::participantJoined, this, &Room::onParticipantJoined); connect(room, &Models::Room::participantJoined, this, &Room::onParticipantJoined);
connect(room, &Models::Room::participantLeft, this, &Room::onParticipantLeft); connect(room, &Models::Room::participantLeft, this, &Room::onParticipantLeft);
feed->setModel(p_room->feed);
} }
Room::~Room() Room::~Room()