mirror of
https://gitlab.linphone.org/BC/public/linphone-desktop.git
synced 2026-01-17 11:28:07 +00:00
- Chat room loading optimization.
- Fix loading more chat entries when going to beginning. - Fix right padding text in chat messages. - Fix black screen videos.
This commit is contained in:
parent
3be835d378
commit
3aab79261e
24 changed files with 229 additions and 180 deletions
|
|
@ -54,22 +54,41 @@ Camera::Camera (QQuickItem *parent) : QQuickFramebufferObject(parent) {
|
|||
mRefreshTimer->start();
|
||||
}
|
||||
|
||||
class SafeFramebuffer : public QQuickFramebufferObject::Renderer{
|
||||
public:
|
||||
SafeFramebuffer(){}
|
||||
QOpenGLFramebufferObject *createFramebufferObject (const QSize &size) override{
|
||||
return new QOpenGLFramebufferObject(size);
|
||||
}
|
||||
void render () override{}
|
||||
void synchronize (QQuickFramebufferObject *item) override{}
|
||||
};
|
||||
|
||||
QQuickFramebufferObject::Renderer *Camera::createRenderer () const {
|
||||
QQuickFramebufferObject::Renderer * renderer = NULL;
|
||||
if(mIsPreview){
|
||||
CoreManager::getInstance()->getCore()->setNativePreviewWindowId(NULL);// Reset
|
||||
renderer=(QQuickFramebufferObject::Renderer *)CoreManager::getInstance()->getCore()->getNativePreviewWindowId();
|
||||
return renderer;
|
||||
CoreManager::getInstance()->getCore()->setNativePreviewWindowId(renderer);
|
||||
}else{
|
||||
auto call = mCallModel->getCall();
|
||||
if(call){
|
||||
call->setNativeVideoWindowId(NULL);// Reset
|
||||
return (QQuickFramebufferObject::Renderer *) call->getNativeVideoWindowId();
|
||||
renderer = (QQuickFramebufferObject::Renderer *) call->getNativeVideoWindowId();
|
||||
call->setNativeVideoWindowId(renderer);
|
||||
}else{
|
||||
CoreManager::getInstance()->getCore()->setNativeVideoWindowId(NULL);
|
||||
return (QQuickFramebufferObject::Renderer *) CoreManager::getInstance()->getCore()->getNativeVideoWindowId();
|
||||
renderer = (QQuickFramebufferObject::Renderer *) CoreManager::getInstance()->getCore()->getNativeVideoWindowId();
|
||||
CoreManager::getInstance()->getCore()->setNativeVideoWindowId(renderer);
|
||||
}
|
||||
}
|
||||
|
||||
if(renderer)
|
||||
return renderer;
|
||||
else{
|
||||
qWarning() << "Camera stream couldn't start for Rendering";
|
||||
return new SafeFramebuffer();
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -88,6 +88,7 @@ QQuickFramebufferObject::Renderer *CameraPreview::createRenderer () const {
|
|||
QQuickFramebufferObject::Renderer * renderer;
|
||||
CoreManager::getInstance()->getCore()->setNativePreviewWindowId(NULL);// Reset
|
||||
renderer=(QQuickFramebufferObject::Renderer *)CoreManager::getInstance()->getCore()->getNativePreviewWindowId();
|
||||
CoreManager::getInstance()->getCore()->setNativePreviewWindowId(renderer);
|
||||
if(renderer)
|
||||
return renderer;
|
||||
else{
|
||||
|
|
|
|||
|
|
@ -525,6 +525,9 @@ bool ChatRoomModel::getIsRemoteComposing () const {
|
|||
return mComposers.size() > 0;
|
||||
}
|
||||
|
||||
bool ChatRoomModel::isEntriesLoading() const{
|
||||
return mEntriesLoading;
|
||||
}
|
||||
|
||||
std::shared_ptr<linphone::ChatRoom> ChatRoomModel::getChatRoom(){
|
||||
return mChatRoom;
|
||||
|
|
@ -885,6 +888,7 @@ void ChatRoomModel::updateNewMessageNotice(const int& count){
|
|||
}
|
||||
|
||||
void ChatRoomModel::initEntries(){
|
||||
qDebug() << "Internal Entries : Init";
|
||||
// On call : reinitialize all entries. This allow to free up memory
|
||||
QList<std::shared_ptr<ChatEvent> > entries;
|
||||
QList<EntrySorterHelper> prepareEntries;
|
||||
|
|
@ -909,7 +913,7 @@ void ChatRoomModel::initEntries(){
|
|||
}
|
||||
}
|
||||
EntrySorterHelper::getLimitedSelection(&entries, prepareEntries, mLastEntriesStep, this);
|
||||
|
||||
qDebug() << "Internal Entries : Built";
|
||||
mIsInitialized = true;
|
||||
if(entries.size() >0){
|
||||
beginResetModel();
|
||||
|
|
@ -917,78 +921,95 @@ void ChatRoomModel::initEntries(){
|
|||
updateNewMessageNotice(mChatRoom->getUnreadMessagesCount());
|
||||
endResetModel();
|
||||
}
|
||||
qDebug() << "Internal Entries : End";
|
||||
}
|
||||
void ChatRoomModel::setEntriesLoading(const bool& loading){
|
||||
if( mEntriesLoading != loading){
|
||||
mEntriesLoading = loading;
|
||||
emit entriesLoadingChanged(mEntriesLoading);
|
||||
qApp->processEvents();
|
||||
}
|
||||
}
|
||||
|
||||
int ChatRoomModel::loadMoreEntries(){
|
||||
QList<std::shared_ptr<ChatEvent> > entries;
|
||||
QList<EntrySorterHelper> prepareEntries;
|
||||
// Get current event count for each type
|
||||
QVector<int> entriesCounts;
|
||||
entriesCounts.resize(3);
|
||||
for(auto itEntries = mEntries.begin() ; itEntries != mEntries.end() ; ++itEntries){
|
||||
if( (*itEntries)->mType == MessageEntry)
|
||||
++entriesCounts[0];
|
||||
else if( (*itEntries)->mType == CallEntry){
|
||||
if(dynamic_cast<ChatCallModel*>((*itEntries).get())->mIsStart)
|
||||
++entriesCounts[1];
|
||||
} else
|
||||
++entriesCounts[2];
|
||||
}
|
||||
setEntriesLoading(true);
|
||||
int currentRowCount = rowCount();
|
||||
int newEntries = 0;
|
||||
do{
|
||||
QList<std::shared_ptr<ChatEvent> > entries;
|
||||
QList<EntrySorterHelper> prepareEntries;
|
||||
// Get current event count for each type
|
||||
QVector<int> entriesCounts;
|
||||
entriesCounts.resize(3);
|
||||
for(auto itEntries = mEntries.begin() ; itEntries != mEntries.end() ; ++itEntries){
|
||||
if( (*itEntries)->mType == MessageEntry)
|
||||
++entriesCounts[0];
|
||||
else if( (*itEntries)->mType == CallEntry){
|
||||
if(dynamic_cast<ChatCallModel*>((*itEntries).get())->mIsStart)
|
||||
++entriesCounts[1];
|
||||
} else
|
||||
++entriesCounts[2];
|
||||
}
|
||||
|
||||
// Messages
|
||||
for (auto &message : mChatRoom->getHistoryRange(entriesCounts[0], entriesCounts[0]+mLastEntriesStep)){
|
||||
auto itEntries = mEntries.begin();
|
||||
bool haveEntry = false;
|
||||
while(!haveEntry && itEntries != mEntries.end()){
|
||||
auto entry = dynamic_cast<ChatMessageModel*>(itEntries->get());
|
||||
haveEntry = (entry && entry->getChatMessage() == message);
|
||||
++itEntries;
|
||||
}
|
||||
if(!haveEntry)
|
||||
prepareEntries << EntrySorterHelper(message->getTime() ,MessageEntry, message);
|
||||
}
|
||||
|
||||
// Messages
|
||||
for (auto &message : mChatRoom->getHistoryRange(entriesCounts[0], entriesCounts[0]+mLastEntriesStep)){
|
||||
auto itEntries = mEntries.begin();
|
||||
bool haveEntry = false;
|
||||
while(!haveEntry && itEntries != mEntries.end()){
|
||||
auto entry = dynamic_cast<ChatMessageModel*>(itEntries->get());
|
||||
haveEntry = (entry && entry->getChatMessage() == message);
|
||||
++itEntries;
|
||||
// Calls
|
||||
bool secureChatEnabled = CoreManager::getInstance()->getSettingsModel()->getSecureChatEnabled();
|
||||
bool standardChatEnabled = CoreManager::getInstance()->getSettingsModel()->getStandardChatEnabled();
|
||||
|
||||
if( isOneToOne() && (secureChatEnabled && !standardChatEnabled && isSecure()
|
||||
|| standardChatEnabled && !isSecure()) ) {
|
||||
auto callHistory = CallsListModel::getCallHistory(getParticipantAddress(), Utils::coreStringToAppString(mChatRoom->getLocalAddress()->asStringUriOnly()));
|
||||
int count = 0;
|
||||
auto itCallHistory = callHistory.begin();
|
||||
while(count < entriesCounts[1] && itCallHistory != callHistory.end()){
|
||||
++itCallHistory;
|
||||
++count;
|
||||
}
|
||||
count = 0;
|
||||
while( count < mLastEntriesStep && itCallHistory != callHistory.end()){
|
||||
prepareEntries << EntrySorterHelper((*itCallHistory)->getStartDate(), CallEntry, *itCallHistory);
|
||||
++itCallHistory;
|
||||
}
|
||||
}
|
||||
if(!haveEntry)
|
||||
prepareEntries << EntrySorterHelper(message->getTime() ,MessageEntry, message);
|
||||
}
|
||||
|
||||
// Calls
|
||||
bool secureChatEnabled = CoreManager::getInstance()->getSettingsModel()->getSecureChatEnabled();
|
||||
bool standardChatEnabled = CoreManager::getInstance()->getSettingsModel()->getStandardChatEnabled();
|
||||
|
||||
if( isOneToOne() && (secureChatEnabled && !standardChatEnabled && isSecure()
|
||||
|| standardChatEnabled && !isSecure()) ) {
|
||||
auto callHistory = CallsListModel::getCallHistory(getParticipantAddress(), Utils::coreStringToAppString(mChatRoom->getLocalAddress()->asStringUriOnly()));
|
||||
int count = 0;
|
||||
auto itCallHistory = callHistory.begin();
|
||||
while(count < entriesCounts[1] && itCallHistory != callHistory.end()){
|
||||
++itCallHistory;
|
||||
++count;
|
||||
// Notices
|
||||
for (auto &eventLog : mChatRoom->getHistoryRangeEvents(entriesCounts[2], entriesCounts[2]+mLastEntriesStep)){
|
||||
auto itEntries = mEntries.begin();
|
||||
bool haveEntry = false;
|
||||
while(!haveEntry && itEntries != mEntries.end()){
|
||||
auto entry = dynamic_cast<ChatNoticeModel*>(itEntries->get());
|
||||
haveEntry = (entry && entry->getEventLog() && entry->getEventLog() == eventLog);
|
||||
++itEntries;
|
||||
}
|
||||
if(!haveEntry)
|
||||
prepareEntries << EntrySorterHelper(eventLog->getCreationTime() , NoticeEntry, eventLog);
|
||||
}
|
||||
count = 0;
|
||||
while( count < mLastEntriesStep && itCallHistory != callHistory.end()){
|
||||
prepareEntries << EntrySorterHelper((*itCallHistory)->getStartDate(), CallEntry, *itCallHistory);
|
||||
++itCallHistory;
|
||||
EntrySorterHelper::getLimitedSelection(&entries, prepareEntries, mLastEntriesStep, this);
|
||||
if(entries.size() >0){
|
||||
beginInsertRows(QModelIndex(), 0, entries.size()-1);
|
||||
for(auto entry : entries)
|
||||
mEntries.prepend(entry);
|
||||
endInsertRows();
|
||||
//emit layoutChanged();
|
||||
updateLastUpdateTime();
|
||||
}
|
||||
}
|
||||
// Notices
|
||||
for (auto &eventLog : mChatRoom->getHistoryRangeEvents(entriesCounts[2], entriesCounts[2]+mLastEntriesStep)){
|
||||
auto itEntries = mEntries.begin();
|
||||
bool haveEntry = false;
|
||||
while(!haveEntry && itEntries != mEntries.end()){
|
||||
auto entry = dynamic_cast<ChatNoticeModel*>(itEntries->get());
|
||||
haveEntry = (entry && entry->getEventLog() && entry->getEventLog() == eventLog);
|
||||
++itEntries;
|
||||
}
|
||||
if(!haveEntry)
|
||||
prepareEntries << EntrySorterHelper(eventLog->getCreationTime() , NoticeEntry, eventLog);
|
||||
}
|
||||
EntrySorterHelper::getLimitedSelection(&entries, prepareEntries, mLastEntriesStep, this);
|
||||
if(entries.size() >0){
|
||||
beginInsertRows(QModelIndex(), 0, entries.size()-1);
|
||||
for(auto entry : entries)
|
||||
mEntries.prepend(entry);
|
||||
endInsertRows();
|
||||
emit layoutChanged();
|
||||
updateLastUpdateTime();
|
||||
}
|
||||
return entries.size();
|
||||
newEntries = entries.size();
|
||||
}while( newEntries>0 && currentRowCount == rowCount());
|
||||
currentRowCount = rowCount() - currentRowCount + 1;
|
||||
setEntriesLoading(false);
|
||||
emit moreEntriesLoaded(currentRowCount);
|
||||
return currentRowCount;
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -155,6 +155,8 @@ public:
|
|||
|
||||
Q_PROPERTY(ChatMessageModel * reply READ getReply WRITE setReply NOTIFY replyChanged)
|
||||
|
||||
Q_PROPERTY(bool entriesLoading READ isEntriesLoading WRITE setEntriesLoading NOTIFY entriesLoadingChanged)
|
||||
|
||||
|
||||
|
||||
//ChatRoomModel (const QString &peerAddress, const QString &localAddress, const bool& isSecure);
|
||||
|
|
@ -199,6 +201,7 @@ public:
|
|||
bool isCurrentProxy() const; // Return true if this chat room is Me() is the current proxy
|
||||
bool canHandleParticipants() const;
|
||||
bool getIsRemoteComposing () const;
|
||||
bool isEntriesLoading() const;
|
||||
ParticipantListModel* getParticipants() const;
|
||||
std::shared_ptr<linphone::ChatRoom> getChatRoom();
|
||||
QList<QString> getComposers();
|
||||
|
|
@ -208,6 +211,7 @@ public:
|
|||
void setSubject(QString& subject);
|
||||
void setLastUpdateTime(const QDateTime& lastUpdateDate);
|
||||
void updateLastUpdateTime();
|
||||
void setEntriesLoading(const bool& loading);
|
||||
|
||||
void setUnreadMessagesCount(const int& count);
|
||||
void setMissedCallsCount(const int& count);
|
||||
|
|
@ -243,6 +247,7 @@ public:
|
|||
bool mDeleteChatRoom = false; // Use as workaround because of core->deleteChatRoom() that call destructor without takking account of count ref : call it in ChatRoomModel destructor
|
||||
int mLastEntriesStep = 50; // Retrieve a part of the history to avoid too much processing
|
||||
bool mMarkAsReadEnabled = true;
|
||||
bool mEntriesLoading = false;
|
||||
|
||||
|
||||
void insertCall (const std::shared_ptr<linphone::CallLog> &callLog);
|
||||
|
|
@ -289,6 +294,8 @@ public slots:
|
|||
|
||||
signals:
|
||||
bool isRemoteComposingChanged ();
|
||||
void entriesLoadingChanged(const bool& loading);
|
||||
void moreEntriesLoaded(const int& count);
|
||||
|
||||
void allEntriesRemoved (std::shared_ptr<ChatRoomModel> model);
|
||||
void lastEntryRemoved ();
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
*/
|
||||
|
||||
#include <QQuickWindow>
|
||||
#include <QTimer>
|
||||
|
||||
#include "app/App.hpp"
|
||||
#include "components/core/CoreManager.hpp"
|
||||
|
|
@ -140,16 +141,16 @@ void ChatRoomProxyModel::compose (const QString& text) {
|
|||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void ChatRoomProxyModel::loadMoreEntries () {
|
||||
void ChatRoomProxyModel::loadMoreEntriesAsync(){
|
||||
QTimer::singleShot(10, this, &ChatRoomProxyModel::loadMoreEntries);
|
||||
}
|
||||
|
||||
void ChatRoomProxyModel::onMoreEntriesLoaded(const int& count){
|
||||
emit moreEntriesLoaded(count);
|
||||
}
|
||||
void ChatRoomProxyModel::loadMoreEntries() {
|
||||
if(mChatRoomModel ) {
|
||||
int currentRowCount = rowCount();
|
||||
int newEntries = 0;
|
||||
do{
|
||||
newEntries = mChatRoomModel->loadMoreEntries();
|
||||
invalidate();
|
||||
}while( newEntries>0 && currentRowCount == rowCount());
|
||||
currentRowCount = rowCount() - currentRowCount + 1;
|
||||
emit moreEntriesLoaded(currentRowCount);
|
||||
mChatRoomModel->loadMoreEntries();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -228,7 +229,6 @@ QString ChatRoomProxyModel::getFullPeerAddress () const {
|
|||
void ChatRoomProxyModel::setFullPeerAddress (const QString &peerAddress) {
|
||||
mFullPeerAddress = peerAddress;
|
||||
emit fullPeerAddressChanged(mFullPeerAddress);
|
||||
//reload();
|
||||
}
|
||||
|
||||
QString ChatRoomProxyModel::getFullLocalAddress () const {
|
||||
|
|
@ -238,7 +238,6 @@ QString ChatRoomProxyModel::getFullLocalAddress () const {
|
|||
void ChatRoomProxyModel::setFullLocalAddress (const QString &localAddress) {
|
||||
mFullLocalAddress = localAddress;
|
||||
emit fullLocalAddressChanged(mFullLocalAddress);
|
||||
//reload();
|
||||
}
|
||||
|
||||
bool ChatRoomProxyModel::markAsReadEnabled() const{
|
||||
|
|
@ -277,6 +276,7 @@ void ChatRoomProxyModel::reload (ChatRoomModel *chatRoomModel) {
|
|||
QObject::disconnect(ChatRoomModel, &ChatRoomModel::messageReceived, this, &ChatRoomProxyModel::handleMessageReceived);
|
||||
QObject::disconnect(ChatRoomModel, &ChatRoomModel::messageSent, this, &ChatRoomProxyModel::handleMessageSent);
|
||||
QObject::disconnect(ChatRoomModel, &ChatRoomModel::markAsReadEnabledChanged, this, &ChatRoomProxyModel::markAsReadEnabledChanged);
|
||||
QObject::disconnect(ChatRoomModel, &ChatRoomModel::moreEntriesLoaded, this, &ChatRoomProxyModel::onMoreEntriesLoaded);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -289,6 +289,7 @@ void ChatRoomProxyModel::reload (ChatRoomModel *chatRoomModel) {
|
|||
QObject::connect(ChatRoomModel, &ChatRoomModel::messageReceived, this, &ChatRoomProxyModel::handleMessageReceived);
|
||||
QObject::connect(ChatRoomModel, &ChatRoomModel::messageSent, this, &ChatRoomProxyModel::handleMessageSent);
|
||||
QObject::connect(ChatRoomModel, &ChatRoomModel::markAsReadEnabledChanged, this, &ChatRoomProxyModel::markAsReadEnabledChanged);
|
||||
QObject::connect(ChatRoomModel, &ChatRoomModel::moreEntriesLoaded, this, &ChatRoomProxyModel::onMoreEntriesLoaded);
|
||||
}
|
||||
|
||||
static_cast<ChatRoomModelFilter *>(sourceModel())->setSourceModel(mChatRoomModel.get());
|
||||
|
|
|
|||
|
|
@ -55,6 +55,8 @@ public:
|
|||
Q_INVOKABLE QString getDisplayNameComposers()const;
|
||||
Q_INVOKABLE QVariant getAt(int row);
|
||||
|
||||
|
||||
Q_INVOKABLE void loadMoreEntriesAsync ();
|
||||
Q_INVOKABLE void loadMoreEntries ();
|
||||
Q_INVOKABLE void setEntryTypeFilter (int type);
|
||||
|
||||
|
|
@ -73,6 +75,9 @@ public:
|
|||
|
||||
Q_INVOKABLE void setFilterText(const QString& text);
|
||||
|
||||
public slots:
|
||||
void onMoreEntriesLoaded(const int& count);
|
||||
|
||||
signals:
|
||||
void peerAddressChanged (const QString &peerAddress);
|
||||
void localAddressChanged (const QString &localAddress);
|
||||
|
|
|
|||
|
|
@ -102,10 +102,7 @@ void TimelineModel::setSelected(const bool& selected){
|
|||
mChatRoomModel->initEntries();
|
||||
}
|
||||
emit selectedChanged(mSelected);
|
||||
}else if(selected)// Warning, Setting to true is only when we want to force a selection. It's why we send a signal only in this case. We want avoid to change the counter on timelines that are already unselected.
|
||||
// This only work because we want at least only one timeline selected
|
||||
emit selectedChanged(mSelected);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void TimelineModel::updateUnreadCount(){
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ BusyIndicator {
|
|||
RotationAnimator {
|
||||
duration: BusyIndicatorStyle.duration
|
||||
loops: Animation.Infinite
|
||||
running: busyIndicator.visible && busyIndicator.running
|
||||
running: true
|
||||
target: item
|
||||
|
||||
from: 0
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ Item {
|
|||
property bool colorOverwriteEnabled : false
|
||||
mipmap: SettingsModel.mipmapEnabled
|
||||
cache: Images.areReadOnlyImages
|
||||
asynchronous: true
|
||||
|
||||
//anchors.centerIn: parent
|
||||
anchors.fill: parent
|
||||
|
|
|
|||
|
|
@ -41,8 +41,8 @@ ListView {
|
|||
policy: (view.contentHeight > view.height ? ScrollBar.AlwaysOn : ScrollBar.AlwaysOff)
|
||||
}
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
boundsMovement: Flickable.StopAtBounds
|
||||
boundsBehavior: Flickable.DragOverBounds
|
||||
clip: true
|
||||
contentWidth: width - (vScrollBar.visible?vScrollBar.width:0)
|
||||
spacing: 0
|
||||
|
|
|
|||
|
|
@ -31,53 +31,53 @@
|
|||
// =============================================================================
|
||||
|
||||
function initView () {
|
||||
chat.tryToLoadMoreEntries = false
|
||||
chat.bindToEnd = true
|
||||
chat.bindToEnd = true
|
||||
chat.positionViewAtEnd()
|
||||
if(chat.atYBeginning && !chat.loadingEntries){//Check if we are at beginning
|
||||
chat.displaying = true
|
||||
container.proxyModel.loadMoreEntriesAsync()
|
||||
}
|
||||
}
|
||||
|
||||
function getComponentFromEntry (chatEntry) {
|
||||
|
||||
if (chatEntry.type === Linphone.ChatRoomModel.CallEntry) {
|
||||
return 'Event.qml'
|
||||
}
|
||||
|
||||
if (chatEntry.type === Linphone.ChatRoomModel.NoticeEntry) {
|
||||
return 'Notice.qml'
|
||||
}
|
||||
|
||||
return chatEntry.isOutgoing ? 'OutgoingMessage.qml' : 'IncomingMessage.qml'
|
||||
|
||||
if (chatEntry.type === Linphone.ChatRoomModel.CallEntry) {
|
||||
return 'Event.qml'
|
||||
}
|
||||
|
||||
if (chatEntry.type === Linphone.ChatRoomModel.NoticeEntry) {
|
||||
return 'Notice.qml'
|
||||
}
|
||||
|
||||
return chatEntry.isOutgoing ? 'OutgoingMessage.qml' : 'IncomingMessage.qml'
|
||||
}
|
||||
|
||||
function handleFilesDropped (files) {
|
||||
chat.bindToEnd = true
|
||||
files.forEach(container.proxyModel.sendFileMessage)
|
||||
chat.bindToEnd = true
|
||||
files.forEach(container.proxyModel.sendFileMessage)
|
||||
}
|
||||
|
||||
function handleMoreEntriesLoaded (n) {
|
||||
chat.positionViewAtIndex(n - 1, QtQuick.ListView.Beginning)
|
||||
chat.positionViewAtIndex(n - 1, QtQuick.ListView.Beginning)
|
||||
}
|
||||
|
||||
function handleMovementEnded () {
|
||||
if (chat.atYEnd) {
|
||||
chat.bindToEnd = true
|
||||
}
|
||||
if (chat.atYEnd) {
|
||||
chat.bindToEnd = true
|
||||
}
|
||||
}
|
||||
|
||||
function handleMovementStarted () {
|
||||
chat.bindToEnd = false
|
||||
chat.bindToEnd = false
|
||||
}
|
||||
|
||||
function handleTextChanged (text) {
|
||||
container.proxyModel.compose(text)
|
||||
container.proxyModel.compose(text)
|
||||
}
|
||||
|
||||
function sendMessage (text) {
|
||||
textArea.text = ''
|
||||
chat.bindToEnd = true
|
||||
if(container.proxyModel)
|
||||
container.proxyModel.sendMessage(text)
|
||||
/*
|
||||
else{// Create a chat room
|
||||
CallsListModel.createChat()
|
||||
}*/
|
||||
textArea.text = ''
|
||||
chat.bindToEnd = true
|
||||
if(container.proxyModel)
|
||||
container.proxyModel.sendMessage(text)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,61 +39,42 @@ Rectangle {
|
|||
id: chat
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
property bool bindToEnd: false
|
||||
property bool tryToLoadMoreEntries: true
|
||||
//property var sipAddressObserver: SipAddressesModel.getSipAddressObserver(proxyModel.fullPeerAddress, proxyModel.fullLocalAddress)
|
||||
property bool displaying: false
|
||||
property int loaderCount: 0
|
||||
property int readyItems : 0
|
||||
property bool loadingLoader: (readyItems != loaderCount)
|
||||
property bool loadingEntries: container.proxyModel.chatRoomModel.entriesLoading || displaying
|
||||
property bool tryToLoadMoreEntries: loadingEntries || loadingLoader
|
||||
property bool isMoving : false // replace moving read-only property to allow using movement signals.
|
||||
|
||||
onLoadingEntriesChanged: {
|
||||
if( loadingEntries && !displaying)
|
||||
displaying = true
|
||||
}
|
||||
//property var sipAddressObserver: SipAddressesModel.getSipAddressObserver(proxyModel.fullPeerAddress, proxyModel.fullLocalAddress)
|
||||
// -----------------------------------------------------------------------
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
|
||||
highlightFollowsCurrentItem: false
|
||||
|
||||
// Use moving event => this is a user action.
|
||||
onIsMovingChanged:{
|
||||
if(!chat.isMoving && chat.atYBeginning && !chat.loadingEntries){// Moving has stopped. Check if we are at beginning
|
||||
chat.displaying = true
|
||||
container.proxyModel.loadMoreEntriesAsync()
|
||||
}
|
||||
}
|
||||
section {
|
||||
criteria: ViewSection.FullString
|
||||
delegate: sectionHeading
|
||||
property: '$sectionDate'
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: loadMoreEntriesDelayer
|
||||
interval: 1
|
||||
repeat: false
|
||||
running: false
|
||||
|
||||
onTriggered: {
|
||||
chat.positionViewAtBeginning()
|
||||
container.proxyModel.loadMoreEntries()
|
||||
}
|
||||
}
|
||||
Timer {
|
||||
// Delay each search by 100ms
|
||||
id: endOfLoadMoreEntriesDelayer
|
||||
interval: 100
|
||||
repeat: false
|
||||
running: false
|
||||
|
||||
onTriggered: {
|
||||
if(chat.atYBeginning){// We are still at the beginning. Try to continue searching
|
||||
loadMoreEntriesDelayer.start()
|
||||
}else// We are not at the begining. New search can be done by moving to the top.
|
||||
chat.tryToLoadMoreEntries = false
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
Component.onCompleted: Logic.initView()
|
||||
|
||||
onContentYChanged: {
|
||||
if (chat.atYBeginning && !chat.tryToLoadMoreEntries) {
|
||||
chat.tryToLoadMoreEntries = true// Show busy indicator
|
||||
loadMoreEntriesDelayer.start()// Let GUI time to the busy indicator to be shown
|
||||
}
|
||||
}
|
||||
onMovementEnded: Logic.handleMovementEnded()
|
||||
onMovementStarted: Logic.handleMovementStarted()
|
||||
onMovementStarted: {Logic.handleMovementStarted(); chat.isMoving = true}
|
||||
onMovementEnded: {Logic.handleMovementEnded(); chat.isMoving = false}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
|
|
@ -104,12 +85,10 @@ Rectangle {
|
|||
// the position is set at end and it can be possible to load
|
||||
// more entries.
|
||||
onEntryTypeFilterChanged: Logic.initView()
|
||||
|
||||
onMoreEntriesLoaded: {
|
||||
Logic.handleMoreEntriesLoaded(n)
|
||||
if(n>1)// New entries : delay the end
|
||||
endOfLoadMoreEntriesDelayer.start()
|
||||
else// No new entries, we can stop without waiting
|
||||
chat.tryToLoadMoreEntries = false
|
||||
Logic.handleMoreEntriesLoaded(n)// move view to n - 1 item
|
||||
chat.displaying = false
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -258,8 +237,18 @@ Rectangle {
|
|||
// Display content.
|
||||
Loader {
|
||||
id: loader
|
||||
height: (item !== null && typeof(item)!== 'undefined')? item.height: 0
|
||||
Layout.fillWidth: true
|
||||
source: Logic.getComponentFromEntry($chatEntry)
|
||||
property int count: 0
|
||||
asynchronous: chat.count - count > 100
|
||||
onStatusChanged: if( status == Loader.Ready) ++chat.readyItems
|
||||
Component.onCompleted: count = ++chat.loaderCount
|
||||
Component.onDestruction: {
|
||||
--chat.loaderCount
|
||||
if( status == Loader.Ready)
|
||||
--chat.readyItems
|
||||
}
|
||||
}
|
||||
Connections{
|
||||
target: loader.item
|
||||
|
|
@ -300,16 +289,17 @@ Rectangle {
|
|||
width: parent.width
|
||||
Text {
|
||||
id: composersItem
|
||||
property var composers : container.proxyModel.chatRoomModel && container.proxyModel.chatRoomModel.composers
|
||||
property var composers : container.proxyModel.chatRoomModel ? container.proxyModel.chatRoomModel.composers : undefined
|
||||
property int count : composers && composers.length ? composers.length : 0
|
||||
color: ChatStyle.composingText.color
|
||||
font.pointSize: ChatStyle.composingText.pointSize
|
||||
height: visible ? undefined : 0
|
||||
leftPadding: ChatStyle.composingText.leftPadding
|
||||
visible: composers && composers.length > 0 && ( (!proxyModel.chatRoomModel.haveEncryption && SettingsModel.standardChatEnabled)
|
||||
visible: count > 0 && ( (!proxyModel.chatRoomModel.haveEncryption && SettingsModel.standardChatEnabled)
|
||||
|| (proxyModel.chatRoomModel.haveEncryption && SettingsModel.secureChatEnabled) )
|
||||
wrapMode: Text.Wrap
|
||||
//: '%1 is typing...' indicate that someone is composing in chat
|
||||
text:(!composers || composers.length==0?'': qsTr('chatTyping','',composers.length).arg(container.proxyModel.getDisplayNameComposers()))
|
||||
text:(count==0?'': qsTr('chatTyping','',count).arg(container.proxyModel.getDisplayNameComposers()))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ TextEdit {
|
|||
property string lastTextSelected : ''
|
||||
property font customFont : SettingsModel.textMessageFont
|
||||
property int fitHeight: visible ? contentHeight + padding : 0
|
||||
property int fitWidth: visible ? implicitWidth + padding*2 : 0
|
||||
property int fitWidth: visible ? implicitWidth + 2: 0 // add 2 because there is a bug on border that lead to not fit text exactly
|
||||
|
||||
signal rightClicked()
|
||||
|
||||
|
|
@ -36,10 +36,12 @@ TextEdit {
|
|||
visible: contentModel && contentModel.isText()
|
||||
clip: true
|
||||
padding: ChatStyle.entry.message.padding
|
||||
textMargin: 0
|
||||
readOnly: true
|
||||
selectByMouse: true
|
||||
font.family: customFont.family
|
||||
font.pointSize: Units.dp * customFont.pointSize
|
||||
|
||||
text: visible ? Utils.encodeTextToQmlRichFormat(contentModel.text, {
|
||||
imagesHeight: ChatStyle.entry.message.images.height,
|
||||
imagesWidth: ChatStyle.entry.message.images.width
|
||||
|
|
@ -51,7 +53,7 @@ TextEdit {
|
|||
textFormat: Text.RichText // To supports links and imgs.
|
||||
wrapMode: TextEdit.Wrap
|
||||
|
||||
onCursorRectangleChanged: if(!readOnly) Logic.ensureVisible(cursorRectangle)
|
||||
//onCursorRectangleChanged: if(!readOnly) Logic.ensureVisible(cursorRectangle)
|
||||
onLinkActivated: Qt.openUrlExternally(link)
|
||||
onSelectedTextChanged:{
|
||||
if(selectedText != '') lastTextSelected = selectedText
|
||||
|
|
|
|||
|
|
@ -93,8 +93,7 @@ DialogPlus {
|
|||
updateSelectionModels: false
|
||||
anchors.fill: parent
|
||||
model: TimelineProxyModel{}
|
||||
onEntrySelected:{
|
||||
console.log(entry)
|
||||
onEntryClicked:{
|
||||
if( entry ) {
|
||||
mainItem.chatRoomSelectedCallback(entry.chatRoomModel)
|
||||
exit(1)
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ function loadMoreEntries () {
|
|||
if (history.atYBeginning && !history.tryToLoadMoreEntries) {
|
||||
history.tryToLoadMoreEntries = true
|
||||
history.positionViewAtBeginning()
|
||||
container.proxyModel.loadMoreEntries()
|
||||
container.proxyModel.loadMoreEntriesAsync()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ Rectangle {
|
|||
|
||||
Component.onCompleted: Logic.initView()
|
||||
|
||||
onContentYChanged: Logic.loadMoreEntries()
|
||||
onContentYChanged: Logic.loadMoreEntriesAsync()
|
||||
onMovementEnded: Logic.handleMovementEnded()
|
||||
onMovementStarted: Logic.handleMovementStarted()
|
||||
|
||||
|
|
|
|||
|
|
@ -86,6 +86,7 @@ Notification {
|
|||
onClicked: notification._close(function () {
|
||||
AccountSettingsModel.setDefaultProxyConfigFromSipAddress(notification.localAddress)
|
||||
notification.timelineModel.selected = true
|
||||
console.log("Load conversation from notification")
|
||||
notification.notificationData.window.setView('Conversation', {
|
||||
chatRoomModel:notification.timelineModel.getChatRoomModel()
|
||||
})
|
||||
|
|
|
|||
|
|
@ -164,7 +164,7 @@ QtObject {
|
|||
}
|
||||
|
||||
property QtObject message: QtObject {
|
||||
property int padding: 8
|
||||
property int padding: 10
|
||||
property int radius: 4
|
||||
|
||||
property QtObject extraContent: QtObject {
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ Rectangle {
|
|||
|
||||
//signal entrySelected (string entry)
|
||||
signal entrySelected (TimelineModel entry)
|
||||
signal entryClicked(TimelineModel entry)
|
||||
signal showHistoryRequest()
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
|
@ -329,8 +330,8 @@ Rectangle {
|
|||
preventStealing: false
|
||||
onClicked: {
|
||||
if(mouse.button == Qt.LeftButton){
|
||||
if(modelData.selected || !view.updateSelectionModels)// Update selection
|
||||
timeline.entrySelected(modelData)
|
||||
//if(modelData.selected || !view.updateSelectionModels)// Update selection
|
||||
timeline.entryClicked(modelData)
|
||||
if(view){
|
||||
if(view.updateSelectionModels)
|
||||
modelData.selected = true
|
||||
|
|
|
|||
|
|
@ -216,8 +216,6 @@ Window {
|
|||
fullPeerAddress: window.call.fullPeerAddress
|
||||
fullLocalAddress: window.call.fullLocalAddress
|
||||
localAddress: window.call.localAddress
|
||||
|
||||
onChatRoomModelChanged: if(chatRoomModel) chatRoomModel.initEntries()
|
||||
}
|
||||
|
||||
Connections {
|
||||
|
|
|
|||
|
|
@ -240,6 +240,7 @@ ColumnLayout {
|
|||
sipAddresses: _contact ? _contact.vcard.sipAddresses : [ contactEdit.sipAddress ]
|
||||
|
||||
function vewConversation(chatRoomModel){
|
||||
console.log("Load conversation from contact edit")
|
||||
window.setView('Conversation', {
|
||||
chatRoomModel:chatRoomModel
|
||||
}, function(){
|
||||
|
|
|
|||
|
|
@ -204,6 +204,7 @@ ColumnLayout {
|
|||
Connections{
|
||||
target: lastChatRoom
|
||||
onStateChanged: if(state === 1) {
|
||||
console.log("Load conversation from contacts")
|
||||
window.setView('Conversation', {
|
||||
chatRoomModel: lastChatRoom
|
||||
})
|
||||
|
|
|
|||
|
|
@ -455,7 +455,7 @@ ColumnLayout {
|
|||
anchors.leftMargin: 50
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
//anchors.horizontalCenter: parent.horizontalCenter
|
||||
visible: chatArea.tryingToLoadMoreEntries
|
||||
running: chatArea.tryingToLoadMoreEntries
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
|
@ -527,7 +527,6 @@ ColumnLayout {
|
|||
id:chatArea
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
|
||||
proxyModel: ChatRoomProxyModel {
|
||||
id: chatRoomProxyModel
|
||||
|
||||
|
|
|
|||
|
|
@ -319,10 +319,12 @@ ApplicationWindow {
|
|||
|
||||
onEntrySelected:{
|
||||
if( entry ) {
|
||||
window.setView('Conversation', {
|
||||
chatRoomModel:entry.chatRoomModel
|
||||
|
||||
if( entry.selected){
|
||||
console.log("Load conversation from entry selected on timeline")
|
||||
window.setView('Conversation', {
|
||||
chatRoomModel:entry.chatRoomModel
|
||||
})
|
||||
}
|
||||
}else{
|
||||
|
||||
window.setView('Home', {})
|
||||
|
|
@ -364,11 +366,14 @@ ApplicationWindow {
|
|||
Connections {
|
||||
target: UrlHandlers
|
||||
|
||||
onSip: window.setView('Conversation', {
|
||||
onSip: {
|
||||
console.log("Change conversation from url handler")
|
||||
window.setView('Conversation', {
|
||||
peerAddress: sipAddress,
|
||||
localAddress: AccountSettingsModel.sipAddress,
|
||||
fullPeerAddress: sipAddress,
|
||||
fullLocalAddress: AccountSettingsModel.fullSipAddress
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue