mirror of
https://gitlab.linphone.org/BC/public/linphone-desktop.git
synced 2026-01-23 14:48:15 +00:00
unstable, supports calls in chat
This commit is contained in:
parent
74be020133
commit
bcee4d9d19
11 changed files with 181 additions and 25 deletions
|
|
@ -34,6 +34,7 @@ set(SOURCES
|
|||
src/app/Database.cpp
|
||||
src/app/Logger.cpp
|
||||
src/components/chat/ChatModel.cpp
|
||||
src/components/chat/ChatProxyModel.cpp
|
||||
src/components/contacts/ContactModel.cpp
|
||||
src/components/contacts/ContactsListModel.cpp
|
||||
src/components/contacts/ContactsListProxyModel.cpp
|
||||
|
|
@ -52,6 +53,7 @@ set(HEADERS
|
|||
src/app/Database.hpp
|
||||
src/app/Logger.hpp
|
||||
src/components/chat/ChatModel.hpp
|
||||
src/components/chat/ChatProxyModel.hpp
|
||||
src/components/contacts/ContactModel.hpp
|
||||
src/components/contacts/ContactsListModel.hpp
|
||||
src/components/contacts/ContactsListProxyModel.hpp
|
||||
|
|
|
|||
|
|
@ -194,6 +194,10 @@
|
|||
<source>endCall</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>outgoingCall</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>Home</name>
|
||||
|
|
|
|||
|
|
@ -194,6 +194,10 @@
|
|||
<source>endCall</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>outgoingCall</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>Home</name>
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
#include <QQuickView>
|
||||
#include <QtDebug>
|
||||
|
||||
#include "../components/chat/ChatModel.hpp"
|
||||
#include "../components/chat/ChatProxyModel.hpp"
|
||||
#include "../components/contacts/ContactModel.hpp"
|
||||
#include "../components/contacts/ContactsListModel.hpp"
|
||||
#include "../components/contacts/ContactsListProxyModel.hpp"
|
||||
|
|
@ -99,6 +99,7 @@ void App::registerTypes () {
|
|||
qmlRegisterType<ContactsListProxyModel>("Linphone", 1, 0, "ContactsListProxyModel");
|
||||
|
||||
qmlRegisterType<ChatModel>("Linphone", 1, 0, "ChatModel");
|
||||
qmlRegisterType<ChatProxyModel>("Linphone", 1, 0, "ChatProxyModel");
|
||||
|
||||
// Register singletons.
|
||||
qmlRegisterSingletonType<ContactsListModel>(
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
#include <algorithm>
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QtDebug>
|
||||
|
||||
|
|
@ -79,6 +81,38 @@ void ChatModel::removeAllEntries () {
|
|||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
void ChatModel::fillMessageEntry (
|
||||
QVariantMap &dest,
|
||||
const shared_ptr<linphone::ChatMessage> &message
|
||||
) {
|
||||
dest["type"] = EntryType::MessageEntry;
|
||||
dest["timestamp"] = QDateTime::fromTime_t(message->getTime());
|
||||
dest["content"] = Utils::linphoneStringToQString(
|
||||
message->getText()
|
||||
);
|
||||
dest["isOutgoing"] = message->isOutgoing();
|
||||
}
|
||||
|
||||
void ChatModel::fillCallStartEntry (
|
||||
QVariantMap &dest,
|
||||
const std::shared_ptr<linphone::CallLog> &call_log
|
||||
) {
|
||||
QDateTime timestamp = QDateTime::fromTime_t(call_log->getStartDate());
|
||||
|
||||
dest["type"] = EntryType::CallEntry;
|
||||
dest["timestamp"] = timestamp;
|
||||
dest["isOutgoing"] = call_log->getDir() == linphone::CallDirOutgoing;
|
||||
dest["status"] = call_log->getStatus();
|
||||
}
|
||||
|
||||
void ChatModel::fillCallEndEntry (
|
||||
QVariantMap &dest,
|
||||
const std::shared_ptr<linphone::CallLog> &call_log
|
||||
) {
|
||||
|
||||
|
||||
}
|
||||
|
||||
void ChatModel::removeEntry (ChatEntryData &pair) {
|
||||
int type = pair.first["type"].toInt();
|
||||
|
||||
|
|
@ -89,7 +123,9 @@ void ChatModel::removeEntry (ChatEntryData &pair) {
|
|||
);
|
||||
break;
|
||||
case ChatModel::CallEntry:
|
||||
|
||||
CoreManager::getInstance()->getCore()->removeCallLog(
|
||||
static_pointer_cast<linphone::CallLog>(pair.second)
|
||||
);
|
||||
break;
|
||||
default:
|
||||
qWarning() << "Unknown chat entry type:" << type;
|
||||
|
|
@ -114,29 +150,42 @@ void ChatModel::setSipAddress (const QString &sip_address) {
|
|||
// Invalid old sip address entries.
|
||||
m_entries.clear();
|
||||
|
||||
m_chat_room =
|
||||
CoreManager::getInstance()->getCore()->getChatRoomFromUri(
|
||||
Utils::qStringToLinphoneString(sip_address)
|
||||
);
|
||||
shared_ptr<linphone::Core> core = CoreManager::getInstance()->getCore();
|
||||
string std_sip_address = Utils::qStringToLinphoneString(sip_address);
|
||||
|
||||
m_chat_room = core->getChatRoomFromUri(std_sip_address);
|
||||
|
||||
// Get messages.
|
||||
for (auto &message : m_chat_room->getHistory(0)) {
|
||||
QVariantMap map;
|
||||
|
||||
map["type"] = EntryType::MessageEntry;
|
||||
map["timestamp"] = QDateTime::fromTime_t(message->getTime());
|
||||
map["content"] = Utils::linphoneStringToQString(
|
||||
message->getText()
|
||||
);
|
||||
map["isOutgoing"] = message->isOutgoing();
|
||||
|
||||
fillMessageEntry(map, message);
|
||||
m_entries << qMakePair(map, static_pointer_cast<void>(message));
|
||||
}
|
||||
|
||||
// Get calls.
|
||||
// TODO.
|
||||
for (auto &call_log : core->getCallHistoryForAddress(m_chat_room->getPeerAddress())) {
|
||||
QVariantMap start, end;
|
||||
fillCallStartEntry(start, call_log);
|
||||
|
||||
ChatEntryData pair = qMakePair(start, static_pointer_cast<void>(call_log));
|
||||
|
||||
auto it = lower_bound(
|
||||
m_entries.begin(), m_entries.end(), pair,
|
||||
[](const ChatEntryData &a, const ChatEntryData &b) {
|
||||
return a.first["timestamp"] < b.first["timestamp"];
|
||||
}
|
||||
);
|
||||
|
||||
m_entries.insert(it, pair);
|
||||
}
|
||||
|
||||
endResetModel();
|
||||
|
||||
emit sipAddressChanged(sip_address);
|
||||
}
|
||||
|
||||
// QT_TR_NOOP('endCall'),
|
||||
// QT_TR_NOOP('incomingCall'),
|
||||
// QT_TR_NOOP('lostIncomingCall'),
|
||||
// QT_TR_NOOP('lostOutgoingCall')
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@
|
|||
// ===================================================================
|
||||
|
||||
class ChatModel : public QAbstractListModel {
|
||||
friend class ChatProxyModel;
|
||||
|
||||
Q_OBJECT;
|
||||
|
||||
Q_PROPERTY(
|
||||
|
|
@ -16,6 +18,9 @@ class ChatModel : public QAbstractListModel {
|
|||
NOTIFY sipAddressChanged
|
||||
);
|
||||
|
||||
signals:
|
||||
void sipAddressChanged (const QString &sipAddress);
|
||||
|
||||
public:
|
||||
enum Roles {
|
||||
ChatEntry = Qt::DisplayRole,
|
||||
|
|
@ -28,6 +33,13 @@ public:
|
|||
};
|
||||
Q_ENUM(EntryType);
|
||||
|
||||
enum CallStatus {
|
||||
CallStatusDeclined = linphone::CallStatusDeclined,
|
||||
CallStatusMissed = linphone::CallStatusMissed,
|
||||
CallStatusSuccess = linphone::CallStatusSuccess
|
||||
};
|
||||
Q_ENUM(CallStatus);
|
||||
|
||||
ChatModel (QObject *parent = Q_NULLPTR) : QAbstractListModel(parent) {}
|
||||
|
||||
int rowCount (const QModelIndex &index = QModelIndex()) const {
|
||||
|
|
@ -44,12 +56,24 @@ public slots:
|
|||
void removeEntry (int id);
|
||||
void removeAllEntries ();
|
||||
|
||||
signals:
|
||||
void sipAddressChanged (const QString &sipAddress);
|
||||
|
||||
private:
|
||||
typedef QPair<QVariantMap, std::shared_ptr<void> > ChatEntryData;
|
||||
|
||||
void fillMessageEntry (
|
||||
QVariantMap &dest,
|
||||
const std::shared_ptr<linphone::ChatMessage> &message
|
||||
);
|
||||
|
||||
void fillCallStartEntry (
|
||||
QVariantMap &dest,
|
||||
const std::shared_ptr<linphone::CallLog> &call_log
|
||||
);
|
||||
|
||||
void fillCallEndEntry (
|
||||
QVariantMap &dest,
|
||||
const std::shared_ptr<linphone::CallLog> &call_log
|
||||
);
|
||||
|
||||
void removeEntry (ChatEntryData &pair);
|
||||
|
||||
QString getSipAddress () const;
|
||||
|
|
|
|||
13
tests/src/components/chat/ChatProxyModel.cpp
Normal file
13
tests/src/components/chat/ChatProxyModel.cpp
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
#include "ChatProxyModel.hpp"
|
||||
|
||||
// ===================================================================
|
||||
|
||||
ChatProxyModel::ChatProxyModel (QObject *parent) : QSortFilterProxyModel(parent) {
|
||||
m_chat_model.setParent(this);
|
||||
setSourceModel(&m_chat_model);
|
||||
setFilterCaseSensitivity(Qt::CaseInsensitive);
|
||||
}
|
||||
|
||||
bool ChatProxyModel::filterAcceptsRow (int source_row, const QModelIndex &source_parent) const {
|
||||
return true; // TODO.
|
||||
}
|
||||
44
tests/src/components/chat/ChatProxyModel.hpp
Normal file
44
tests/src/components/chat/ChatProxyModel.hpp
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
#ifndef CHAT_PROXY_MODEL_H_
|
||||
#define CHAT_PROXY_MODEL_H_
|
||||
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
#include "ChatModel.hpp"
|
||||
|
||||
class ChatProxyModel : public QSortFilterProxyModel {
|
||||
Q_OBJECT;
|
||||
|
||||
Q_PROPERTY(
|
||||
QString sipAddress
|
||||
READ getSipAddress
|
||||
WRITE setSipAddress
|
||||
NOTIFY sipAddressChanged
|
||||
);
|
||||
|
||||
signals:
|
||||
void sipAddressChanged (const QString &sipAddress);
|
||||
|
||||
public:
|
||||
ChatProxyModel (QObject *parent = Q_NULLPTR);
|
||||
|
||||
public slots:
|
||||
ChatModel *getChatModel () {
|
||||
return &m_chat_model;
|
||||
}
|
||||
|
||||
protected:
|
||||
bool filterAcceptsRow (int source_row, const QModelIndex &source_parent) const;
|
||||
|
||||
private:
|
||||
QString getSipAddress () const {
|
||||
return m_chat_model.getSipAddress();
|
||||
}
|
||||
|
||||
void setSipAddress (const QString &sip_address) {
|
||||
m_chat_model.setSipAddress(sip_address);
|
||||
}
|
||||
|
||||
ChatModel m_chat_model;
|
||||
};
|
||||
|
||||
#endif // CHAT_PROXY_MODEL_H_
|
||||
|
|
@ -11,6 +11,7 @@ import Linphone.Styles 1.0
|
|||
ColumnLayout {
|
||||
property var contact
|
||||
|
||||
// Can be a model or a proxy chat model.
|
||||
property alias model: chat.model
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
|
|
@ -80,12 +81,18 @@ ColumnLayout {
|
|||
delegate: Rectangle {
|
||||
id: entry
|
||||
|
||||
// Chat supports model and proxy model.
|
||||
function getModel () {
|
||||
var model = chat.model
|
||||
return model.getChatModel ? model.getChatModel() : model
|
||||
}
|
||||
|
||||
function isHoverEntry () {
|
||||
return mouseArea.containsMouse
|
||||
}
|
||||
|
||||
function removeEntry () {
|
||||
chat.model.removeEntry(index)
|
||||
getModel().removeEntry(index)
|
||||
}
|
||||
|
||||
anchors {
|
||||
|
|
|
|||
|
|
@ -1,18 +1,27 @@
|
|||
import QtQuick 2.7
|
||||
|
||||
import Common 1.0
|
||||
import Linphone 1.0
|
||||
import Linphone.Styles 1.0
|
||||
import Utils 1.0
|
||||
|
||||
// ===================================================================
|
||||
|
||||
Row {
|
||||
property string _type: {
|
||||
if ($chatEntry.status === ChatModel.CallStatusSuccess) {
|
||||
return $chatEntry.isOutgoing ? 'outgoing_call' : 'incoming_call'
|
||||
}
|
||||
|
||||
return ''
|
||||
}
|
||||
|
||||
height: ChatStyle.entry.lineHeight
|
||||
spacing: ChatStyle.entry.message.extraContent.spacing
|
||||
|
||||
Icon {
|
||||
height: parent.height
|
||||
icon: $content
|
||||
icon: _type
|
||||
iconSize: ChatStyle.entry.event.iconSize
|
||||
width: ChatStyle.entry.metaWidth
|
||||
}
|
||||
|
|
@ -25,8 +34,7 @@ Row {
|
|||
property var i18n: [
|
||||
QT_TR_NOOP('endCall'),
|
||||
QT_TR_NOOP('incomingCall'),
|
||||
QT_TR_NOOP('lostIncomingCall'),
|
||||
QT_TR_NOOP('lostOutgoingCall')
|
||||
QT_TR_NOOP('outgoingCall')
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -37,7 +45,7 @@ Row {
|
|||
pointSize: ChatStyle.entry.event.text.fontSize
|
||||
}
|
||||
height: parent.height
|
||||
text: qsTr(Utils.snakeToCamel($content))
|
||||
text: qsTr(Utils.snakeToCamel(_type))
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ ColumnLayout {
|
|||
descriptionText: qsTr('removeAllEntriesDescription'),
|
||||
exitHandler: function (status) {
|
||||
if (status) {
|
||||
chatModel.removeAllEntries()
|
||||
chatProxyModel.removeAllEntries()
|
||||
}
|
||||
},
|
||||
title: qsTr('removeAllEntriesTitle')
|
||||
|
|
@ -145,8 +145,8 @@ ColumnLayout {
|
|||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
contact: parent._contact
|
||||
model: ChatModel {
|
||||
id: chatModel
|
||||
model: ChatProxyModel {
|
||||
id: chatProxyModel
|
||||
|
||||
sipAddress: conversation.sipAddress
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue