- 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:
Julien Wadel 2022-01-26 15:37:08 +01:00
parent 3be835d378
commit 3aab79261e
24 changed files with 229 additions and 180 deletions

View file

@ -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();
}
}
// -----------------------------------------------------------------------------

View file

@ -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{

View file

@ -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;
}
//-------------------------------------------------

View file

@ -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 ();

View file

@ -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());

View file

@ -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);

View file

@ -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(){

View file

@ -39,7 +39,7 @@ BusyIndicator {
RotationAnimator {
duration: BusyIndicatorStyle.duration
loops: Animation.Infinite
running: busyIndicator.visible && busyIndicator.running
running: true
target: item
from: 0

View file

@ -35,6 +35,7 @@ Item {
property bool colorOverwriteEnabled : false
mipmap: SettingsModel.mipmapEnabled
cache: Images.areReadOnlyImages
asynchronous: true
//anchors.centerIn: parent
anchors.fill: parent

View file

@ -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

View file

@ -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)
}

View file

@ -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()))
}
}

View file

@ -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

View file

@ -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)

View file

@ -38,7 +38,7 @@ function loadMoreEntries () {
if (history.atYBeginning && !history.tryToLoadMoreEntries) {
history.tryToLoadMoreEntries = true
history.positionViewAtBeginning()
container.proxyModel.loadMoreEntries()
container.proxyModel.loadMoreEntriesAsync()
}
}

View file

@ -49,7 +49,7 @@ Rectangle {
Component.onCompleted: Logic.initView()
onContentYChanged: Logic.loadMoreEntries()
onContentYChanged: Logic.loadMoreEntriesAsync()
onMovementEnded: Logic.handleMovementEnded()
onMovementStarted: Logic.handleMovementStarted()

View file

@ -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()
})

View file

@ -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 {

View file

@ -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

View file

@ -216,8 +216,6 @@ Window {
fullPeerAddress: window.call.fullPeerAddress
fullLocalAddress: window.call.fullLocalAddress
localAddress: window.call.localAddress
onChatRoomModelChanged: if(chatRoomModel) chatRoomModel.initEntries()
}
Connections {

View file

@ -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(){

View file

@ -204,6 +204,7 @@ ColumnLayout {
Connections{
target: lastChatRoom
onStateChanged: if(state === 1) {
console.log("Load conversation from contacts")
window.setView('Conversation', {
chatRoomModel: lastChatRoom
})

View file

@ -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

View file

@ -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
})
}
}
}