diff --git a/CHANGELOG.md b/CHANGELOG.md index 024ce7e20..e07a0a005 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - OAuth2 connection to retrieve remote provisioning (Experimental and not usable without configuration). - Add/View contact from a message. - Mute option for each chatrooms. +- New Chat Layout. ## 5.0.11 - undefined diff --git a/linphone-app/assets/languages/da.ts b/linphone-app/assets/languages/da.ts index 86f306933..d59b94375 100644 --- a/linphone-app/assets/languages/da.ts +++ b/linphone-app/assets/languages/da.ts @@ -2215,6 +2215,11 @@ Klik her: <a href="%1">%1</a> 'New messages received!' Notification that warn the user of new messages. + + newConferenceInvitation + 'Conference invitation received!' : Notification about receiving an invitation to a conference. + + OnlineInstallerDialog diff --git a/linphone-app/assets/languages/de.ts b/linphone-app/assets/languages/de.ts index d1be49498..de0b005d8 100644 --- a/linphone-app/assets/languages/de.ts +++ b/linphone-app/assets/languages/de.ts @@ -2215,6 +2215,11 @@ Klicken Sie hier: <a href="%1">%1</a> 'New messages received!' Notification that warn the user of new messages. + + newConferenceInvitation + 'Conference invitation received!' : Notification about receiving an invitation to a conference. + + OnlineInstallerDialog diff --git a/linphone-app/assets/languages/en.ts b/linphone-app/assets/languages/en.ts index ce34206f0..3146b9396 100644 --- a/linphone-app/assets/languages/en.ts +++ b/linphone-app/assets/languages/en.ts @@ -2215,6 +2215,11 @@ Click here: <a href="%1">%1</a> 'New messages received!' Notification that warn the user of new messages. New messages received! + + newConferenceInvitation + 'Conference invitation received!' : Notification about receiving an invitation to a conference. + Conference invitation received! + OnlineInstallerDialog diff --git a/linphone-app/assets/languages/es.ts b/linphone-app/assets/languages/es.ts index ebd873a8e..f16ebb924 100644 --- a/linphone-app/assets/languages/es.ts +++ b/linphone-app/assets/languages/es.ts @@ -2215,6 +2215,11 @@ Haga clic aquí: <a href="%1">%1 </a> 'New messages received!' Notification that warn the user of new messages. + + newConferenceInvitation + 'Conference invitation received!' : Notification about receiving an invitation to a conference. + + OnlineInstallerDialog diff --git a/linphone-app/assets/languages/fr_FR.ts b/linphone-app/assets/languages/fr_FR.ts index 771ed783e..c0da5979f 100644 --- a/linphone-app/assets/languages/fr_FR.ts +++ b/linphone-app/assets/languages/fr_FR.ts @@ -2215,6 +2215,11 @@ Cliquez ici : <a href="%1">%1</a> 'New messages received!' Notification that warn the user of new messages. Nouveaux messages arrivés ! + + newConferenceInvitation + 'Conference invitation received!' : Notification about receiving an invitation to a conference. + + OnlineInstallerDialog diff --git a/linphone-app/assets/languages/hu.ts b/linphone-app/assets/languages/hu.ts index d284ab57e..255eb9672 100644 --- a/linphone-app/assets/languages/hu.ts +++ b/linphone-app/assets/languages/hu.ts @@ -2202,6 +2202,11 @@ Kattintson ide: <a href="%1">%1</a> 'New messages received!' Notification that warn the user of new messages. + + newConferenceInvitation + 'Conference invitation received!' : Notification about receiving an invitation to a conference. + + OnlineInstallerDialog diff --git a/linphone-app/assets/languages/it.ts b/linphone-app/assets/languages/it.ts index 585b308c1..a32597a2c 100644 --- a/linphone-app/assets/languages/it.ts +++ b/linphone-app/assets/languages/it.ts @@ -2215,6 +2215,11 @@ Clicca: <a href="%1">%1</a> 'New messages received!' Notification that warn the user of new messages. E' stato ricevuto un nuovo messaggio! + + newConferenceInvitation + 'Conference invitation received!' : Notification about receiving an invitation to a conference. + + OnlineInstallerDialog diff --git a/linphone-app/assets/languages/ja.ts b/linphone-app/assets/languages/ja.ts index e881da227..a59dfe225 100644 --- a/linphone-app/assets/languages/ja.ts +++ b/linphone-app/assets/languages/ja.ts @@ -2202,6 +2202,11 @@ 'New messages received!' Notification that warn the user of new messages. + + newConferenceInvitation + 'Conference invitation received!' : Notification about receiving an invitation to a conference. + + OnlineInstallerDialog diff --git a/linphone-app/assets/languages/lt.ts b/linphone-app/assets/languages/lt.ts index 3fbd15949..0650c5675 100644 --- a/linphone-app/assets/languages/lt.ts +++ b/linphone-app/assets/languages/lt.ts @@ -2228,6 +2228,11 @@ Spustelėkite čia: <a href="%1">%1</a> 'New messages received!' Notification that warn the user of new messages. + + newConferenceInvitation + 'Conference invitation received!' : Notification about receiving an invitation to a conference. + + OnlineInstallerDialog diff --git a/linphone-app/assets/languages/pt_BR.ts b/linphone-app/assets/languages/pt_BR.ts index cd0007ef0..305a3715a 100644 --- a/linphone-app/assets/languages/pt_BR.ts +++ b/linphone-app/assets/languages/pt_BR.ts @@ -2215,6 +2215,11 @@ Clique aqui: <a href="%1">%1 </a> 'New messages received!' Notification that warn the user of new messages. + + newConferenceInvitation + 'Conference invitation received!' : Notification about receiving an invitation to a conference. + + OnlineInstallerDialog diff --git a/linphone-app/assets/languages/ru.ts b/linphone-app/assets/languages/ru.ts index e92ae1bc4..be17030fe 100644 --- a/linphone-app/assets/languages/ru.ts +++ b/linphone-app/assets/languages/ru.ts @@ -2228,6 +2228,11 @@ 'New messages received!' Notification that warn the user of new messages. Получены новые сообщения! + + newConferenceInvitation + 'Conference invitation received!' : Notification about receiving an invitation to a conference. + + OnlineInstallerDialog diff --git a/linphone-app/assets/languages/sv.ts b/linphone-app/assets/languages/sv.ts index 52c4bd2a3..71c4e24d6 100644 --- a/linphone-app/assets/languages/sv.ts +++ b/linphone-app/assets/languages/sv.ts @@ -2215,6 +2215,11 @@ Klicka här: <a href="%1">%1</a> 'New messages received!' Notification that warn the user of new messages. + + newConferenceInvitation + 'Conference invitation received!' : Notification about receiving an invitation to a conference. + + OnlineInstallerDialog diff --git a/linphone-app/assets/languages/tr.ts b/linphone-app/assets/languages/tr.ts index 83631d8fe..d1c333740 100644 --- a/linphone-app/assets/languages/tr.ts +++ b/linphone-app/assets/languages/tr.ts @@ -2202,6 +2202,11 @@ Buraya tıklayın: <a href="%1">%1</a> 'New messages received!' Notification that warn the user of new messages. + + newConferenceInvitation + 'Conference invitation received!' : Notification about receiving an invitation to a conference. + + OnlineInstallerDialog diff --git a/linphone-app/assets/languages/uk.ts b/linphone-app/assets/languages/uk.ts index 5e7e2bca5..068e51048 100644 --- a/linphone-app/assets/languages/uk.ts +++ b/linphone-app/assets/languages/uk.ts @@ -2228,6 +2228,11 @@ 'New messages received!' Notification that warn the user of new messages. + + newConferenceInvitation + 'Conference invitation received!' : Notification about receiving an invitation to a conference. + + OnlineInstallerDialog diff --git a/linphone-app/assets/languages/zh_CN.ts b/linphone-app/assets/languages/zh_CN.ts index 9b5e16f57..37186c1bd 100644 --- a/linphone-app/assets/languages/zh_CN.ts +++ b/linphone-app/assets/languages/zh_CN.ts @@ -2202,6 +2202,11 @@ 'New messages received!' Notification that warn the user of new messages. + + newConferenceInvitation + 'Conference invitation received!' : Notification about receiving an invitation to a conference. + + OnlineInstallerDialog diff --git a/linphone-app/resources.qrc b/linphone-app/resources.qrc index e82f84e91..8cb1da927 100644 --- a/linphone-app/resources.qrc +++ b/linphone-app/resources.qrc @@ -331,6 +331,7 @@ ui/modules/Linphone/Chat/Chat.qml ui/modules/Linphone/Chat/ChatContent.qml ui/modules/Linphone/Chat/ChatDeliveries.qml + ui/modules/Linphone/Chat/ChatFullContent.qml ui/modules/Linphone/Chat/ChatMenu.qml ui/modules/Linphone/Chat/ChatAudioMessage.qml ui/modules/Linphone/Chat/ChatAudioPreview.qml diff --git a/linphone-app/src/components/chat-room/ChatRoomProxyModel.cpp b/linphone-app/src/components/chat-room/ChatRoomProxyModel.cpp index fd37071b3..75e6b10ae 100644 --- a/linphone-app/src/components/chat-room/ChatRoomProxyModel.cpp +++ b/linphone-app/src/components/chat-room/ChatRoomProxyModel.cpp @@ -40,9 +40,9 @@ QString ChatRoomProxyModel::gCachedText; // ============================================================================= -ChatRoomProxyModel::ChatRoomProxyModel (QObject *parent) : QSortFilterProxyModel(parent) { +ChatRoomProxyModel::ChatRoomProxyModel (QObject *parent) : SortFilterProxyModel(parent) { mMarkAsReadEnabled = true; - + mDeleteSourceModel= false; App *app = App::getInstance(); QObject::connect(app->getMainWindow(), &QWindow::activeChanged, this, [this]() { handleIsActiveChanged(App::getInstance()->getMainWindow()); diff --git a/linphone-app/src/components/chat-room/ChatRoomProxyModel.hpp b/linphone-app/src/components/chat-room/ChatRoomProxyModel.hpp index 39a5dc675..95866a746 100644 --- a/linphone-app/src/components/chat-room/ChatRoomProxyModel.hpp +++ b/linphone-app/src/components/chat-room/ChatRoomProxyModel.hpp @@ -21,7 +21,7 @@ #ifndef CHAT_ROOM_PROXY_MODEL_H_ #define CHAT_ROOM_PROXY_MODEL_H_ -#include +#include "app/proxyModel/SortFilterProxyModel.hpp" #include "ChatRoomModel.hpp" @@ -29,7 +29,7 @@ class QWindow; -class ChatRoomProxyModel : public QSortFilterProxyModel { +class ChatRoomProxyModel : public SortFilterProxyModel { class ChatRoomModelFilter; Q_OBJECT diff --git a/linphone-app/src/components/content/ContentProxyModel.cpp b/linphone-app/src/components/content/ContentProxyModel.cpp index 0d140a06d..285861fd4 100644 --- a/linphone-app/src/components/content/ContentProxyModel.cpp +++ b/linphone-app/src/components/content/ContentProxyModel.cpp @@ -63,9 +63,25 @@ bool ContentProxyModel::filterAcceptsRow ( int sourceRow, const QModelIndex &sourceParent ) const { - Q_UNUSED(sourceRow) - Q_UNUSED(sourceParent) - return true; + + bool show = false; + + if (mFilter == FilterContentType::All) + show = true; + else{ + QModelIndex index = sourceModel()->index(sourceRow, 0, QModelIndex()); + auto contentModel = sourceModel()->data(index).value(); + + if( mFilter == FilterContentType::Text && contentModel->isText()) + show = true; + else if( mFilter == FilterContentType::Voice && contentModel->isVoiceRecording()) + show = true; + else if( mFilter == FilterContentType::Conference && contentModel->getConferenceInfoModel()) + show = true; + else if( mFilter == FilterContentType::File && !contentModel->isIcalendar() && (contentModel->isFile() || contentModel->isFileTransfer()|| contentModel->isFileEncrypted()) && !contentModel->isVoiceRecording() ) + show = true; + } + return show; } bool ContentProxyModel::lessThan (const QModelIndex &left, const QModelIndex &right) const { @@ -98,4 +114,15 @@ void ContentProxyModel::remove(ContentModel * model){ void ContentProxyModel::clear(){ qobject_cast(sourceModel())->clear(); +} + +ContentProxyModel::FilterContentType ContentProxyModel::getFilter() const{ + return mFilter; +} +void ContentProxyModel::setFilter(const FilterContentType& contentType){ + if(contentType != mFilter){ + mFilter = contentType; + emit filterChanged(); + invalidate(); + } } \ No newline at end of file diff --git a/linphone-app/src/components/content/ContentProxyModel.hpp b/linphone-app/src/components/content/ContentProxyModel.hpp index d0e6c75f9..fa4055e7b 100644 --- a/linphone-app/src/components/content/ContentProxyModel.hpp +++ b/linphone-app/src/components/content/ContentProxyModel.hpp @@ -39,10 +39,24 @@ class ContentProxyModel : public QSortFilterProxyModel { public: ContentProxyModel (QObject *parent = nullptr); Q_PROPERTY(ChatMessageModel * chatMessageModel READ getChatMessageModel WRITE setChatMessageModel NOTIFY chatMessageModelChanged) + Q_PROPERTY(FilterContentType filter READ getFilter WRITE setFilter NOTIFY filterChanged) + + enum FilterContentType { + All, + File, + Text, + Voice, + Conference, + Unknown + }; + Q_ENUM(FilterContentType) ChatMessageModel * getChatMessageModel() const; + void setChatMessageModel(ChatMessageModel * message); + FilterContentType getFilter() const; + void setFilter(const FilterContentType& contentType); Q_INVOKABLE void setContentListModel(ContentListModel * model); Q_INVOKABLE void addFile(const QString& path); Q_INVOKABLE void remove(ContentModel * model); @@ -50,13 +64,14 @@ public: signals: void chatMessageModelChanged(); + void filterChanged(); protected: virtual bool filterAcceptsRow (int sourceRow, const QModelIndex &sourceParent) const override; virtual bool lessThan (const QModelIndex &left, const QModelIndex &right) const override; std::shared_ptr mContents; - + FilterContentType mFilter = All; }; #endif diff --git a/linphone-app/src/components/notifier/Notifier.cpp b/linphone-app/src/components/notifier/Notifier.cpp index 75a707824..498377128 100644 --- a/linphone-app/src/components/notifier/Notifier.cpp +++ b/linphone-app/src/components/notifier/Notifier.cpp @@ -288,6 +288,9 @@ void Notifier::notifyReceivedMessages (const listhasConferenceInvitationContent()) + //: 'Conference invitation received!' : Notification about receiving an invitation to a conference. + txt = tr("newConferenceInvitation"); }else //: 'New messages received!' Notification that warn the user of new messages. txt = tr("newChatRoomMessages"); diff --git a/linphone-app/src/components/other/colors/ColorListModel.hpp b/linphone-app/src/components/other/colors/ColorListModel.hpp index 2f386f48c..3ca9d7bdf 100644 --- a/linphone-app/src/components/other/colors/ColorListModel.hpp +++ b/linphone-app/src/components/other/colors/ColorListModel.hpp @@ -76,8 +76,14 @@ class ColorListModel : public ProxyListModel { ADD_COLOR("n", "#A1A1A1", "Primary color for pressed button") ADD_COLOR("o", "#D0D8DE", "Primary color for disabled button") - ADD_COLOR("outgoing_bg","#F3F3F3","Outgoing message background") - ADD_COLOR("incoming_bg","#D0D8DE","Incoming message background") + ADD_COLOR("outgoing_bg","#FFEEE5","Outgoing message background") + ADD_COLOR("incoming_bg","#F3F3F3","Incoming message background") + + ADD_COLOR("outgoing_reply_mark_bg","#FF9E67","Outgoing reply message mark background") + ADD_COLOR("incoming_reply_mark_bg","#9B9B9B","Incoming reply message mark background") + + ADD_COLOR("reply_file_bg","#F4F4F4","File icon background in reply") + ADD_COLOR("extension_file_border","#DEDEDE","File icon border in reply") ADD_COLOR("primary_accept", "#9ECD1D", "Primary color for accepting button") diff --git a/linphone-app/src/utils/Utils.cpp b/linphone-app/src/utils/Utils.cpp index a2d963991..51840c771 100644 --- a/linphone-app/src/utils/Utils.cpp +++ b/linphone-app/src/utils/Utils.cpp @@ -125,8 +125,8 @@ QString Utils::toTimeString(QDateTime date, const QString& format){ return getOffsettedUTC(date).toString(format); } -QString Utils::toDateString(QDateTime date){ - return getOffsettedUTC(date).toString("yyyy/MM/dd"); +QString Utils::toDateString(QDateTime date, const QString& format){ + return getOffsettedUTC(date).toString(format); } QString Utils::getDisplayName(const QString& address){ diff --git a/linphone-app/src/utils/Utils.hpp b/linphone-app/src/utils/Utils.hpp index 4c82dfc67..b14104e9b 100644 --- a/linphone-app/src/utils/Utils.hpp +++ b/linphone-app/src/utils/Utils.hpp @@ -61,7 +61,7 @@ public: static QDateTime getOffsettedUTC(const QDateTime& date); Q_INVOKABLE static QString toDateTimeString(QDateTime date); Q_INVOKABLE static QString toTimeString(QDateTime date, const QString& format = "hh:mm:ss"); - Q_INVOKABLE static QString toDateString(QDateTime date); + Q_INVOKABLE static QString toDateString(QDateTime date, const QString& format = "yyyy/MM/dd"); Q_INVOKABLE static QString getDisplayName(const QString& address); Q_INVOKABLE static QString getInitials(const QString& username); // Support UTF32 Q_INVOKABLE static QString toString(const LinphoneEnums::TunnelMode& mode); diff --git a/linphone-app/ui/modules/Linphone/Chat/Chat.qml b/linphone-app/ui/modules/Linphone/Chat/Chat.qml index 3227cffba..4cce4b47e 100644 --- a/linphone-app/ui/modules/Linphone/Chat/Chat.qml +++ b/linphone-app/ui/modules/Linphone/Chat/Chat.qml @@ -97,13 +97,7 @@ Rectangle { container.proxyModel.loadMoreEntriesAsync() } } - section { - criteria: ViewSection.FullString - delegate: sectionHeading - property: '$sectionDate' - } // ----------------------------------------------------------------------- - Component.onCompleted: Logic.initView() onMovementStarted: {Logic.handleMovementStarted(); chat.isMoving = true} onMovementEnded: {Logic.handleMovementEnded(); chat.isMoving = false} @@ -124,47 +118,6 @@ Rectangle { } } - // ----------------------------------------------------------------------- - // Heading. - // ----------------------------------------------------------------------- - - Component { - id: sectionHeading - - Item { - implicitHeight: container.height + ChatStyle.sectionHeading.bottomMargin - width: parent.width - clip: false - Borders { - id: container - - borderColor: ChatStyle.sectionHeading.border.colorModel.color - bottomWidth: ChatStyle.sectionHeading.border.width - implicitHeight: text.contentHeight + - ChatStyle.sectionHeading.padding * 2 + - ChatStyle.sectionHeading.border.width * 2 - topWidth: ChatStyle.sectionHeading.border.width - width: parent.width - - Text { - id: text - - anchors.fill: parent - color: ChatStyle.sectionHeading.text.colorModel.color - font { - bold: true - pointSize: ChatStyle.sectionHeading.text.pointSize - capitalization: Font.Capitalize - } - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - - text: new Date(section).toLocaleDateString(App.locale) - } - } - } - } - // ----------------------------------------------------------------------- // Message/Event renderer. // ----------------------------------------------------------------------- @@ -174,7 +127,22 @@ Rectangle { property bool isNotice : $chatEntry.type === ChatRoomModel.NoticeEntry property bool isCall : $chatEntry.type === ChatRoomModel.CallEntry property bool isMessage : $chatEntry.type === ChatRoomModel.MessageEntry + property var previousItem : proxyModel.count > 0 && index >0 ? proxyModel.getAt(index-1) : null + property var nextItem : proxyModel.count > 0 ? proxyModel.getAt(index+1) : null // bind to count + property bool displayDate: !Utils.equalDate(new Date($chatEntry.timestamp), new Date()) + property bool isTopGrouped: isGrouped(entry.previousItem, $chatEntry) || false + property bool isBottomGrouped: isGrouped($chatEntry, entry.nextItem) || false + onIsBottomGroupedChanged: if(loader.item) loader.item.isBottomGrouped = isBottomGrouped + onIsTopGroupedChanged: if(loader.item) loader.item.isTopGrouped = isTopGrouped + + function isGrouped(item1, item2){ + return item1 && item2 //Have a previous entry + && item1.type == ChatRoomModel.MessageEntry // Previous entry is a message + && item2.type == ChatRoomModel.MessageEntry // Previous entry is a message + && item2.fromSipAddress == item1.fromSipAddress // Same user + && Math.abs((new Date(item2.timestamp)).getTime() - (new Date(item1.timestamp)).getTime())/1000 < 60 + } function isHoverEntry () { return mouseArea.containsMouse } @@ -182,23 +150,13 @@ Rectangle { function removeEntry () { proxyModel.removeRow(index) } - - anchors { - left: parent ? parent.left : undefined - leftMargin: isNotice?0:ChatStyle.entry.leftMargin - right: parent ? parent.right : undefined - - rightMargin: isNotice?0:ChatStyle.entry.deleteIconSize + - ChatStyle.entry.message.extraContent.spacing + - ChatStyle.entry.message.extraContent.rightMargin + - ChatStyle.entry.message.extraContent.leftMargin + - ChatStyle.entry.message.outgoing.areaSize - } - color: ChatStyle.colorModel.color - implicitHeight: layout.height + ChatStyle.entry.bottomMargin + implicitHeight: layout.height + (entry.isBottomGrouped? 1 : ChatStyle.entry.bottomMargin) + + width: chat.contentWidth // Fill all space clip: false + // --------------------------------------------------------------------- MouseArea { @@ -208,51 +166,37 @@ Rectangle { hoverEnabled: true implicitHeight: layout.height width: parent.width + parent.anchors.rightMargin + anchors.top: parent.top + //anchors.topMargin: (entry.isTopGrouped? 1 : ChatStyle.entry.bottomMargin) clip: false acceptedButtons: Qt.NoButton + onContainsMouseChanged: if(loader.item) loader.item.isHovering = containsMouse ColumnLayout{ id: layout spacing: 0 width: entry.width - Text{ - id:authorName - Layout.leftMargin: timeDisplay.width + 10 + RowLayout{ + id: headerLayout Layout.fillWidth: true - text : $chatEntry.fromDisplayName ? $chatEntry.fromDisplayName : '' - property var previousItem : { - if(index >0) - return proxyModel.getAt(index-1) - else - return null - } - - color: ChatStyle.entry.event.text.colorModel.color - font.pointSize: ChatStyle.entry.event.text.pointSize - visible: isMessage - && $chatEntry != undefined - && !$chatEntry.isOutgoing // Only outgoing - && (!previousItem //No previous entry - || previousItem.type != ChatRoomModel.MessageEntry // Previous entry is a message - || previousItem.fromSipAddress != $chatEntry.fromSipAddress // Different user - || (new Date(previousItem.timestamp)).setHours(0, 0, 0, 0) != (new Date($chatEntry.timestamp)).setHours(0, 0, 0, 0) // Same day == section - ) - } - RowLayout { - - spacing: 0 - width: entry.width - + Layout.alignment: Qt.AlignTop | ($chatEntry.isOutgoing ? Qt.AlignRight : Qt.AlignLeft) + Layout.leftMargin: ChatStyle.entry.metaWidth// + ChatStyle.entry.message.extraContent.spacing + Layout.rightMargin: ChatStyle.entry.message.outgoing.areaSize + spacing:0 // Display time. + visible: !entry.isTopGrouped Text { id:timeDisplay - Layout.alignment: Qt.AlignTop - Layout.preferredHeight: ChatStyle.entry.lineHeight - Layout.preferredWidth: ChatStyle.entry.time.width + Layout.alignment: Qt.AlignTop | ($chatEntry.isOutgoing ? Qt.AlignRight : Qt.AlignLeft) + Layout.preferredHeight: implicitHeight// ChatStyle.entry.lineHeight + //Layout.preferredWidth: ChatStyle.entry.time.width color: ChatStyle.entry.event.text.colorModel.color font.pointSize: ChatStyle.entry.time.pointSize - - text: UtilsCpp.toTimeString($chatEntry.timestamp, 'hh:mm') + property bool displayYear: entry.displayDate && (new Date($chatEntry.timestamp)).getFullYear() != (new Date()).getFullYear() + text: $chatEntry + ? (entry.displayDate ? UtilsCpp.toDateString($chatEntry.timestamp, (displayYear ? 'yyyy/':'') + 'MM/dd') + ' ' : '') + + UtilsCpp.toTimeString($chatEntry.timestamp, 'hh:mm') + (authorName.visible ? ' - ' : '') + : '' verticalAlignment: Text.AlignVCenter @@ -261,65 +205,85 @@ Rectangle { } visible:!isNotice } - - // Display content. - Loader { - id: loader - height: (item !== null && typeof(item)!== 'undefined')? item.height: 0 - Layout.fillWidth: true - source: Logic.getComponentFromEntry($chatEntry) - property int loaderIndex: 0 // index of loader from remaining loaders - property int remainingIndex : loaderIndex % ((chat.remainingLoadersCount) / chat.syncLoaderBatch) != 0 // Check loader index to remaining loader. - onRemainingIndexChanged: if( remainingIndex == 0 && asynchronous) asynchronous = false - asynchronous: true - z:1 - - onStatusChanged: if( status == Loader.Ready) { - remainingIndex = -1 // overwrite to remove signal changed. That way, there is no more binding loops. - --chat.remainingLoadersCount // Loader is ready: remove one from remaining count. - } + Text{ + id:authorName + //Layout.leftMargin: timeDisplay.width + ChatStyle.entry.metaWidth + ChatStyle.entry.message.extraContent.spacing + property var displayName: $chatEntry.fromDisplayName ? $chatEntry.fromDisplayName : $chatEntry.name + text : displayName != undefined ? displayName : '' - Component.onCompleted: loaderIndex = ++chat.remainingLoadersCount // on new Loader : one more remaining - Component.onDestruction: if( status != Loader.Ready) --chat.remainingLoadersCount // Remove remaining count if not loaded + color: ChatStyle.entry.event.text.colorModel.color + font.pointSize: ChatStyle.entry.event.text.pointSize + visible: isMessage + && $chatEntry != undefined + && !$chatEntry.isOutgoing // Only outgoing + && (!entry.previousItem //No previous entry + || entry.previousItem.type != ChatRoomModel.MessageEntry // Previous entry is a message + || entry.previousItem.fromSipAddress != $chatEntry.fromSipAddress // Different user + || (new Date(entry.previousItem.timestamp)).setHours(0, 0, 0, 0) != (new Date($chatEntry.timestamp)).setHours(0, 0, 0, 0) // Same day == section + ) + } + } + // Display content. + Loader { + id: loader + height: (item !== null && typeof(item)!== 'undefined')? item.height: 0 + Layout.fillWidth: true + source: Logic.getComponentFromEntry($chatEntry) + property int loaderIndex: 0 // index of loader from remaining loaders + property int remainingIndex : loaderIndex % ((chat.remainingLoadersCount) / chat.syncLoaderBatch) != 0 // Check loader index to remaining loader. + onRemainingIndexChanged: if( remainingIndex == 0 && asynchronous) asynchronous = false + asynchronous: true + z:1 + + onStatusChanged: if( status == Loader.Ready) { + loader.item.isTopGrouped = entry.isTopGrouped + loader.item.isBottomGrouped = entry.isBottomGrouped + remainingIndex = -1 // overwrite to remove signal changed. That way, there is no more binding loops. + --chat.remainingLoadersCount // Loader is ready: remove one from remaining count. + } + + Component.onCompleted: { + loaderIndex = ++chat.remainingLoadersCount // on new Loader : one more remaining + } + Component.onDestruction: if( status != Loader.Ready) --chat.remainingLoadersCount // Remove remaining count if not loaded + } + + Connections{ + target: loader.item + ignoreUnknownSignals: true + //: "Copied to clipboard" : when a user copy a text from the menu, this message show up. + onCopyAllDone: container.noticeBannerText = qsTr("allTextCopied") + //: "Selection copied to clipboard" : when a user copy a text from the menu, this message show up. + onCopySelectionDone: container.noticeBannerText = qsTr("selectedTextCopied") + onReplyClicked: { + proxyModel.chatRoomModel.reply = $chatEntry + } + onForwardClicked:{ + window.attachVirtualWindow(Qt.resolvedUrl('../Dialog/SipAddressDialog.qml') + //: 'Choose where to forward the message' : Dialog title for choosing where to forward the current message. + , {title: qsTr('forwardDialogTitle'), + addressSelectedCallback: function (sipAddress) { + var chat = CallsListModel.createChatRoom( '', proxyModel.chatRoomModel.haveEncryption, [sipAddress], false ) + if(chat){ + chat.chatRoomModel.forwardMessage($chatEntry) + TimelineListModel.select(chat.chatRoomModel) + } + }, + chatRoomSelectedCallback: function (chatRoomModel){ + if(chatRoomModel){ + chatRoomModel.forwardMessage($chatEntry) + TimelineListModel.select(chatRoomModel) + } + } + }) } - Connections{ - target: loader.item - ignoreUnknownSignals: true - //: "Copied to clipboard" : when a user copy a text from the menu, this message show up. - onCopyAllDone: container.noticeBannerText = qsTr("allTextCopied") - //: "Selection copied to clipboard" : when a user copy a text from the menu, this message show up. - onCopySelectionDone: container.noticeBannerText = qsTr("selectedTextCopied") - onReplyClicked: { - proxyModel.chatRoomModel.reply = $chatEntry - } - onForwardClicked:{ - window.attachVirtualWindow(Qt.resolvedUrl('../Dialog/SipAddressDialog.qml') - //: 'Choose where to forward the message' : Dialog title for choosing where to forward the current message. - , {title: qsTr('forwardDialogTitle'), - addressSelectedCallback: function (sipAddress) { - var chat = CallsListModel.createChatRoom( '', proxyModel.chatRoomModel.haveEncryption, [sipAddress], false ) - if(chat){ - chat.chatRoomModel.forwardMessage($chatEntry) - TimelineListModel.select(chat.chatRoomModel) - } - }, - chatRoomSelectedCallback: function (chatRoomModel){ - if(chatRoomModel){ - chatRoomModel.forwardMessage($chatEntry) - TimelineListModel.select(chatRoomModel) - } - } - }) - } - - onGoToMessage:{ - container.goToMessage(message) // sometimes, there is no access to chat id (maybe because of cleaning component while loading new items). Use a global intermediate. - } - onConferenceIcsCopied: container.noticeBannerText = qsTr('conferencesCopiedICS') - onAddContactClicked: container.addContactClicked(contactAddress) - onViewContactClicked: container.viewContactClicked(contactAddress) + onGoToMessage:{ + container.goToMessage(message) // sometimes, there is no access to chat id (maybe because of cleaning component while loading new items). Use a global intermediate. } + onConferenceIcsCopied: container.noticeBannerText = qsTr('conferencesCopiedICS') + onAddContactClicked: container.addContactClicked(contactAddress) + onViewContactClicked: container.viewContactClicked(contactAddress) } } } diff --git a/linphone-app/ui/modules/Linphone/Chat/ChatAudioMessage.qml b/linphone-app/ui/modules/Linphone/Chat/ChatAudioMessage.qml index 56f443955..1c1501b21 100644 --- a/linphone-app/ui/modules/Linphone/Chat/ChatAudioMessage.qml +++ b/linphone-app/ui/modules/Linphone/Chat/ChatAudioMessage.qml @@ -24,8 +24,8 @@ import 'Message.js' as Logic Loader{ id: mainItem property ContentModel contentModel - property int maxWidth : parent.width - property int fitWidth: active ? Math.max(maxWidth - ChatAudioMessageStyle.emptySpace, ChatAudioMessageStyle.minWidth) : 0 + property int availableWidth : parent.width + property int fitWidth: active ? Math.max(availableWidth - ChatAudioMessageStyle.emptySpace, ChatAudioMessageStyle.minWidth) : 0 property int fitHeight: active ? 60 : 0 property font customFont : SettingsModel.textMessageFont @@ -49,7 +49,7 @@ Loader{ property bool isPlaying : vocalPlayer.item && vocalPlayer.item.playbackState === SoundPlayer.PlayingState onIsPlayingChanged: isPlaying ? mediaProgressBar.resume() : mediaProgressBar.stop() - width: maxWidth < 0 || maxWidth > fitWidth ? fitWidth : maxWidth + width: availableWidth < 0 || availableWidth > fitWidth ? fitWidth : availableWidth height: mainItem.fitHeight clip: false diff --git a/linphone-app/ui/modules/Linphone/Chat/ChatCalendarMessage.qml b/linphone-app/ui/modules/Linphone/Chat/ChatCalendarMessage.qml index 78ee5000c..b06553210 100644 --- a/linphone-app/ui/modules/Linphone/Chat/ChatCalendarMessage.qml +++ b/linphone-app/ui/modules/Linphone/Chat/ChatCalendarMessage.qml @@ -25,9 +25,9 @@ Loader{ id: mainItem property ContentModel contentModel property ConferenceInfoModel conferenceInfoModel: contentModel ? contentModel.conferenceInfoModel : null - property int maxWidth : parent.width + property int availableWidth : parent.width property int fitHeight: active && item ? item.fitHeight : 0 - property int fitWidth: active && item ? maxWidth/2 + ChatCalendarMessageStyle.widthMargin*2 : 0 + property int fitWidth: active && item ? availableWidth/2 + ChatCalendarMessageStyle.widthMargin*2 : 0 property bool containsMouse: false property int gotoButtonMode: -1 //-1: hide, 0:goto, 1:MoreInfo property bool isExpanded : false diff --git a/linphone-app/ui/modules/Linphone/Chat/ChatConferenceInvitationMessage.qml b/linphone-app/ui/modules/Linphone/Chat/ChatConferenceInvitationMessage.qml index 85d69a90b..bf7c883ee 100644 --- a/linphone-app/ui/modules/Linphone/Chat/ChatConferenceInvitationMessage.qml +++ b/linphone-app/ui/modules/Linphone/Chat/ChatConferenceInvitationMessage.qml @@ -25,9 +25,9 @@ Loader{ id: mainItem property ContentModel contentModel property ConferenceInfoModel conferenceInfoModel: contentModel ? contentModel.conferenceInfoModel : null - property int maxWidth : parent.width + property int availableWidth : parent.width property int fitHeight: active && item ? item.fitHeight : 0 // + (isExpanded? 200 : 0): 0 - property int fitWidth: active && item ? Math.min(maxWidth > 0 ? maxWidth : 9999999, item.fitWidth + ChatCalendarMessageStyle.widthMargin*2) : 0 + property int fitWidth: active && item ? Math.min(availableWidth > 0 ? availableWidth : 9999999, item.fitWidth + ChatCalendarMessageStyle.widthMargin*2) : 0 property bool containsMouse: false property int gotoButtonMode: -1 //-1: hide, 0:goto, 1:MoreInfo property bool isExpanded : false @@ -56,7 +56,12 @@ Loader{ hoverEnabled: true onClicked: CallsListModel.prepareConferenceCall(mainItem.conferenceInfoModel) - onHoveredChanged: mainItem.containsMouse = loadedItem.containsMouse + onHoveredChanged: mainItem.containsMouse = loadedItem.containsMouse + Rectangle{ + anchors.fill: parent + color: ChatCalendarMessageStyle.backgroundColor.normal.color + radius: 5 + } ColumnLayout{ id: layout @@ -104,7 +109,6 @@ Loader{ elide: Text.ElideRight color: ChatCalendarMessageStyle.subject.colorModel.color font.pointSize: ChatCalendarMessageStyle.subject.pointSize - font.weight: Font.Bold text: mainItem.conferenceInfoModel.subject } RowLayout { diff --git a/linphone-app/ui/modules/Linphone/Chat/ChatContent.qml b/linphone-app/ui/modules/Linphone/Chat/ChatContent.qml index 342adcc03..7c0b12072 100644 --- a/linphone-app/ui/modules/Linphone/Chat/ChatContent.qml +++ b/linphone-app/ui/modules/Linphone/Chat/ChatContent.qml @@ -16,58 +16,199 @@ import LinphoneEnums 1.0 import ColorsList 1.0 // ============================================================================= -Column{ +// Simple content display without reply and forward. These modules need to be splitted because of cyclic dependencies. +// See ChatFullContent + +Loader{// Use of Loader because of Repeater (items cannot be loaded dynamically) id: mainItem - property ContentModel contentModel + property ChatMessageModel chatMessageModel: null + property int availableWidth //const + property int fileWidth: ChatStyle.entry.message.file.height * 4 / 3 + 2*ChatStyle.entry.message.file.margins - property int fitHeight: calendarMessage.fitHeight + message.fitHeight + fileMessage.fitHeight + audioMessage.fitHeight - property int fitWidth: calendarMessage.fitWidth + message.fitWidth + fileMessage.fitWidth + audioMessage.fitWidth - property color backgroundColor - property string lastTextSelected - property alias textColor: message.color - property alias textFont: message.font - property alias fileIsHovering: fileMessage.isHovering + // Readonly + property int bestWidth: Math.min(availableWidth, Math.max(filesBestWidth, conferencesBestWidth, textsBestWidth, voicesBestWidth)) + property int filesBestWidth: 0 + property int filesCount: 0 + property int conferencesCount: 0 + property int conferencesBestWidth: 0 + property int textsBestWidth: 0 + property int textsCount: 0 + property int voicesBestWidth: 0 + property int voicesCount: 0 + signal isFileHoveringChanged(bool isFileHovering) + signal lastTextSelectedChanged(string lastTextSelected) signal rightClicked() signal conferenceIcsCopied() - property int maxWidth - height: fitHeight - anchors.left: parent ? parent.left : undefined - anchors.right: parent ? parent.right : undefined + property bool useTextColor: false + property color textColor - spacing: 0 + property int fileBorderWidth : 0 + property color fileBackgroundColor: ChatStyle.entry.message.file.extension.background.colorModel.color + property int fileBackgroundRadius: ChatStyle.entry.message.file.extension.radius - property bool isOutgoing : contentModel && contentModel.chatMessageModel && (contentModel.chatMessageModel.isOutgoing || contentModel.chatMessageModel.state == LinphoneEnums.ChatMessageStateIdle); - z: message.visible ? 0 : 1 - ChatConferenceInvitationMessage{ - id: calendarMessage - contentModel: mainItem.contentModel - width: parent.width - maxWidth: mainItem.maxWidth - gotoButtonMode: 1 - onExpandToggle: isExpanded=!isExpanded - height: fitHeight - z: 1 - onConferenceIcsCopied:mainItem.conferenceIcsCopied() - } - ChatAudioMessage{ - id: audioMessage - contentModel: mainItem.contentModel - visible: contentModel - z: 1 - } - ChatFileMessage{ - id: fileMessage - contentModel: mainItem.contentModel - width: parent.width - z: 2 - } - ChatTextMessage { - id: message - contentModel: mainItem.contentModel - onLastTextSelectedChanged: mainItem.lastTextSelected = lastTextSelected - color: isOutgoing ? ChatStyle.entry.message.outgoing.text.colorModel.color : ChatStyle.entry.message.incoming.text.colorModel.color - onRightClicked: mainItem.rightClicked() + active: chatMessageModel + + sourceComponent: Component{ + Column{ + id: mainComponent + spacing: 0 + function updateFilesBestWidth(){ + var newBestWidth = 0 + var count = 0 + for(var child in messageFilesList.children) { + var item = messageFilesList.children[child] + if(item){ + var a = item.fitWidth + if(a) { + ++count + newBestWidth = Math.max(newBestWidth,a) + } + } + } + if(count > 1){ + newBestWidth = Math.max(newBestWidth, mainItem.fileWidth*count) + } + mainItem.filesCount = count + mainItem.filesBestWidth = newBestWidth + } + function updateListBestWidth(listView){ + var newBestWidth = 0 + var count = 0 + for(var child in listView.contentItem.children) { + var a = listView.contentItem.children[child].fitWidth + if(a) { + ++count + newBestWidth = Math.max(newBestWidth,a) + } + } + return [count, newBestWidth]; + } + ListView { + id: messagesVoicesList + width: parent.width + visible: count > 0 + spacing: 0 + clip: false + model: ContentProxyModel{ + filter: ContentProxyModel.ContentType.Voice + chatMessageModel: mainItem.chatMessageModel + } + height: contentHeight + boundsBehavior: Flickable.StopAtBounds + interactive: false + function updateBestWidth(){ + var newWidth = mainComponent.updateListBestWidth(messagesVoicesList) + mainItem.voicesCount = newWidth[0] + mainItem.voicesBestWidth = newWidth[1] + } + delegate: ChatAudioMessage{ + id: audioMessage + contentModel: $modelData + visible: contentModel + z: 1 + Component.onCompleted: messagesVoicesList.updateBestWidth() + } + Component.onCompleted: messagesVoicesList.updateBestWidth + } +// CONFERENCE + ListView { + id: messagesConferencesList + width: parent.width + visible: count > 0 + spacing: 0 + clip: false + model: ContentProxyModel{ + filter: ContentProxyModel.ContentType.Conference + chatMessageModel: mainItem.chatMessageModel + } + height: contentHeight + boundsBehavior: Flickable.StopAtBounds + interactive: false + function updateBestWidth(){ + var newWidth = mainComponent.updateListBestWidth(messagesConferencesList) + mainItem.conferencesCount = newWidth[0] + mainItem.conferencesBestWidth = newWidth[1] + } + Component.onCompleted: messagesConferencesList.updateBestWidth() + delegate: ChatConferenceInvitationMessage{ + id: calendarMessage + contentModel: $modelData + width: parent.width + availableWidth: mainItem.availableWidth + gotoButtonMode: 1 + onExpandToggle: isExpanded=!isExpanded + height: fitHeight + z: 1 + onConferenceIcsCopied:mainItem.conferenceIcsCopied() + onFitWidthChanged: messagesConferencesList.updateBestWidth() + Component.onCompleted: messagesConferencesList.updateBestWidth() + } + } +// FILES + GridLayout { + id: messageFilesList + property alias count: repeater.count + visible: count > 0 + clip: false + + property int availableSection: mainItem.availableWidth / mainItem.fileWidth + property int bestFitSection: mainItem.bestWidth / mainItem.fileWidth + columns: Math.max(1, Math.min(availableSection , bestFitSection)) + columnSpacing: 0 + rowSpacing: 0 + width: parent.width + Repeater{ + id: repeater + model: ContentProxyModel{ + filter: ContentProxyModel.ContentType.File + chatMessageModel: mainItem.chatMessageModel + } + ChatFileMessage{ + contentModel: $modelData + onIsHoveringChanged: mainItem.isFileHoveringChanged(isHovering) + borderWidth: mainItem.fileBorderWidth + backgroundColor: mainItem.fileBackgroundColor + backgroundRadius: mainItem.fileBackgroundRadius + Component.onCompleted: mainComponent.updateFilesBestWidth() + } + } + } +// TEXTS + ListView { + id: messagesTextsList + width: parent.width + visible: count > 0 + spacing: 0 + clip: false + model: ContentProxyModel{ + filter: ContentProxyModel.ContentType.Text + chatMessageModel: mainItem.chatMessageModel + } + height: contentHeight + boundsBehavior: Flickable.StopAtBounds + interactive: false + function updateBestWidth(){ + var newWidth = mainComponent.updateListBestWidth(messagesTextsList) + mainItem.textsCount = newWidth[0] + mainItem.textsBestWidth = newWidth[1] + } + Component.onCompleted: messagesTextsList.updateBestWidth() + delegate: + ChatTextMessage { + contentModel: $modelData + onLastTextSelectedChanged: mainItem.lastTextSelectedChanged(lastTextSelected) + color: mainItem.useTextColor + ? mainItem.textColor + : $modelData.isOutgoing + ? ChatStyle.entry.message.outgoing.text.colorModel.color + : ChatStyle.entry.message.incoming.text.colorModel.color + onRightClicked: mainItem.rightClicked() + onFitWidthChanged: messagesTextsList.updateBestWidth() + Component.onCompleted: messagesTextsList.updateBestWidth() + } + } + } } } diff --git a/linphone-app/ui/modules/Linphone/Chat/ChatFileMessage.qml b/linphone-app/ui/modules/Linphone/Chat/ChatFileMessage.qml index f2a22daed..24559f82d 100644 --- a/linphone-app/ui/modules/Linphone/Chat/ChatFileMessage.qml +++ b/linphone-app/ui/modules/Linphone/Chat/ChatFileMessage.qml @@ -19,11 +19,21 @@ Row { property ChatMessageModel chatMessageModel: contentModel && contentModel.chatMessageModel property ContentModel contentModel property bool isOutgoing : chatMessageModel && ( chatMessageModel.isOutgoing || chatMessageModel.state == LinphoneEnums.ChatMessageStateIdle); - property int fitWidth: visible ? Math.max( Math.max((thumbnailProvider.sourceComponent == extension ? thumbnailProvider.item.fitWidth : 0) + property int fitHeight: ChatStyle.entry.message.file.height + property int fitWidth: ChatStyle.entry.message.file.height * 4 / 3 + 2*ChatStyle.entry.message.file.margins + property int borderWidth : 0 + property color backgroundColor: ChatStyle.entry.message.file.extension.background.colorModel.color + property int backgroundRadius: ChatStyle.entry.message.file.extension.radius + /* + property int fitWidth: visible + ? Math.max( Math.max((thumbnailProvider.sourceComponent == extension + ? thumbnailProvider.item.fitWidth + : 0) , thumbnailProvider.width + 3*ChatStyle.entry.message.file.margins) - , Math.max(ChatStyle.entry.message.file.width, ChatStyle.entry.message.outgoing.areaSize)) : 0 + , Math.max(ChatStyle.entry.message.file.width, ChatStyle.entry.message.outgoing.areaSize)) + : 0 property int fitHeight: visible ? rectangle.height : 0 - + */ property bool isAnimatedImage : mainRow.contentModel && mainRow.contentModel.wasDownloaded && UtilsCpp.isAnimatedImage(mainRow.contentModel.filePath) property bool haveThumbnail: mainRow.contentModel && mainRow.contentModel.thumbnail property bool isHovering: thumbnailProvider.state == 'hovered' @@ -32,7 +42,8 @@ Row { signal copySelectionDone() signal forwardClicked() height: fitHeight - visible: contentModel && !contentModel.isIcalendar() && (contentModel.isFile() || contentModel.isFileTransfer()) && !contentModel.isVoiceRecording() + width: fitWidth + visible: true // --------------------------------------------------------------------------- // File message. // --------------------------------------------------------------------------- @@ -56,15 +67,14 @@ Row { property string thumbnail : mainRow.contentModel ? mainRow.contentModel.thumbnail : '' color: 'transparent' anchors.left: parent.left + anchors.right: parent.right anchors.top: parent.top - anchors.leftMargin: ChatStyle.entry.message.file.margins - anchors.topMargin: ChatStyle.entry.message.file.margins - height: 2*ChatStyle.entry.message.file.margins + (mainRow.isAnimatedImage ? ChatStyle.entry.message.file.heightbetter - : thumbnailProvider.sourceComponent == extension ? thumbnailProvider.item.fitHeight - : ChatStyle.entry.message.file.height + height: 2*ChatStyle.entry.message.file.margins + (mainRow.isAnimatedImage + ? ChatStyle.entry.message.file.heightbetter + : thumbnailProvider.sourceComponent == extension + ? ChatStyle.entry.message.file.height + : ChatStyle.entry.message.file.height ) - width: mainRow.width - radius: ChatStyle.entry.message.radius // --------------------------------------------------------------------- @@ -77,12 +87,14 @@ Row { Image { id: thumbnailImageSource property real scaleAnimatorTo : ChatStyle.entry.message.file.animation.thumbnailTo + anchors.centerIn: parent mipmap: SettingsModel.mipmapEnabled source: mainRow.contentModel.thumbnail autoTransform: true fillMode: Image.PreserveAspectFit height: ChatStyle.entry.message.file.height width: height*4/3 + Loader{ anchors.fill: parent sourceComponent: Image{// Better quality on zoom @@ -117,14 +129,18 @@ Row { Rectangle { property int fitWidth: Math.max(downloadText.implicitWidth, Math.max(fileName.visible ? fileName.implicitWidth : 0, fileIcon.iconSize)) + 20 - property int fitHeight: fileIcon.iconSize + (fileName.visible ? fileName.implicitHeight + ChatStyle.entry.message.file.spacing : 0 ) - + (downloadText.visible? downloadText.implicitHeight + ChatStyle.entry.message.file.spacing : 0) + 2*ChatStyle.entry.message.file.margins + //property int fitHeight: fileIcon.iconSize + (fileName.visible ? fileName.implicitHeight + ChatStyle.entry.message.file.spacing : 0 ) +// + (downloadText.visible? downloadText.implicitHeight + ChatStyle.entry.message.file.spacing : 0) + 2*ChatStyle.entry.message.file.margins property real scaleAnimatorTo : ChatStyle.entry.message.file.animation.to - height: fitHeight - width: fitWidth - color: ChatStyle.entry.message.file.extension.background.colorModel.color - radius: ChatStyle.entry.message.file.extension.radius + anchors.centerIn: parent + height: ChatStyle.entry.message.file.height + width: height*4/3 + color: mainRow.backgroundColor + radius: mainRow.backgroundRadius + border.width: mainRow.borderWidth + border.color: ChatStyle.entry.message.file.extension.background.borderColorModel.color + ColumnLayout{ anchors.fill: parent anchors.topMargin: ChatStyle.entry.message.file.margins @@ -135,6 +151,8 @@ Row { Layout.alignment: Qt.AlignCenter icon: extensionText.text != '' ? ChatStyle.entry.message.file.extension.icon : ChatStyle.entry.message.file.extension.unknownIcon iconSize: ChatStyle.entry.message.file.extension.iconSize + Layout.fillHeight: true + Layout.fillWidth: true Layout.preferredHeight: iconSize Layout.preferredWidth: iconSize Text { @@ -176,10 +194,10 @@ Row { visible: mainRow.contentModel && !mainRow.isAnimatedImage && !mainRow.haveThumbnail color: ChatStyle.entry.message.file.extension.text.colorModel.color - elide: Text.ElideRight font.pointSize: ChatStyle.entry.message.file.name.pointSize wrapMode: Text.WrapAnywhere - horizontalAlignment: Qt.AlignCenter + horizontalAlignment: Text.AlignHCenter + maximumLineCount: 2 text: (mainRow.contentModel ? mainRow.contentModel.name : '') } @@ -187,7 +205,7 @@ Row { id: downloadText Layout.fillWidth: true Layout.fillHeight: true - Layout.preferredHeight: visible ? ChatStyle.entry.message.file.download.height : 0 + Layout.preferredHeight: visible ? contentHeight : 0 //: 'Cancel' : Message link to cancel a transfer (upload/download) text: mainRow.contentModel ? rectangle.isTransferring ? qsTr('fileTransferCancel') //: 'Download' : Message link to download a file @@ -197,8 +215,8 @@ Row { font.pointSize: ChatStyle.entry.message.file.download.pointSize color:ChatStyle.entry.message.file.extension.text.colorModel.color visible: (mainRow.contentModel? (!mainItem.isOutgoing && !mainRow.contentModel.wasDownloaded) || rectangle.isTransferring : false) - horizontalAlignment: Qt.AlignCenter - verticalAlignment: Qt.AlignCenter + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter } } @@ -206,7 +224,7 @@ Row { } Loader { id: thumbnailProvider - + anchors.centerIn: parent sourceComponent: (mainRow.contentModel ? (mainRow.isAnimatedImage ? animatedImage : (mainRow.haveThumbnail ? thumbnailImage : extension ) diff --git a/linphone-app/ui/modules/Linphone/Chat/ChatForwardMessage.qml b/linphone-app/ui/modules/Linphone/Chat/ChatForwardMessage.qml index c7136b9e6..8a6789495 100644 --- a/linphone-app/ui/modules/Linphone/Chat/ChatForwardMessage.qml +++ b/linphone-app/ui/modules/Linphone/Chat/ChatForwardMessage.qml @@ -22,13 +22,13 @@ import 'Message.js' as Logic Item { id: mainItem property ChatMessageModel mainChatMessageModel - property int maxWidth : parent.width + property int availableWidth : parent.width property int fitWidth: visible ? headerArea.fitWidth + 7 + ChatForwardMessageStyle.padding * 2 : 0 - property int fitHeight: visible ? icon.height : 0 + property int fitHeight: visible ? icon.height + 5 : 0 property font customFont : SettingsModel.textMessageFont visible: mainChatMessageModel && mainChatMessageModel.isForward - width: maxWidth > fitWidth ? fitWidth : maxWidth + width: availableWidth > fitWidth ? fitWidth : availableWidth height: fitHeight ColumnLayout{ diff --git a/linphone-app/ui/modules/Linphone/Chat/ChatFullContent.qml b/linphone-app/ui/modules/Linphone/Chat/ChatFullContent.qml new file mode 100644 index 000000000..38c2aeae3 --- /dev/null +++ b/linphone-app/ui/modules/Linphone/Chat/ChatFullContent.qml @@ -0,0 +1,66 @@ +import QtQuick 2.7 +import QtQuick.Layouts 1.3 + +import Clipboard 1.0 +import Common 1.0 +import Linphone 1.0 + +import Common.Styles 1.0 +import Linphone.Styles 1.0 +import TextToSpeech 1.0 +import Utils 1.0 +import Units 1.0 +import UtilsCpp 1.0 +import LinphoneEnums 1.0 + +import ColorsList 1.0 + +// ============================================================================= +// Full content display with reply and forward. These modules need to be splitted because of cyclic dependencies. +// See ChatContent + +Column{ + id: mainItem + property ChatMessageModel chatMessageModel: null + property int availableWidth //const + +// Readonly + property int bestWidth: Math.min(availableWidth, Math.max(forwardMessage.fitWidth, replyMessage.fitWidth, chatContent.bestWidth )) + property alias filesBestWidth: chatContent.filesBestWidth + property alias filesCount: chatContent.filesCount + property alias textsBestWidth: chatContent.textsBestWidth + property alias textsCount: chatContent.textsCount + + signal isFileHoveringChanged(bool isFileHovering) + signal lastTextSelectedChanged(string lastTextSelected) + signal rightClicked() + signal conferenceIcsCopied() + signal goToMessage(var message) + + spacing: 0 + ChatForwardMessage{ + id: forwardMessage + mainChatMessageModel: mainItem.chatMessageModel + visible: mainChatMessageModel && mainChatMessageModel.isForward + availableWidth: mainItem.availableWidth + } + ChatReplyMessage{ + id: replyMessage + z: 1 + mainChatMessageModel: mainItem.chatMessageModel + visible: mainChatMessageModel && mainChatMessageModel.isReply + availableWidth: mainItem.availableWidth + onGoToMessage: mainItem.goToMessage(message) + } + ChatContent{ + id: chatContent + chatMessageModel: mainItem.chatMessageModel + availableWidth: mainItem.availableWidth + width: parent.width + + onIsFileHoveringChanged: mainItem.isFileHoveringChanged(isFileHovering) + onLastTextSelectedChanged: mainItem.lastTextSelectedChanged(lastTextSelected) + onRightClicked: mainItem.rightClicked() + onConferenceIcsCopied: mainItem.conferenceIcsCopied() + } +} diff --git a/linphone-app/ui/modules/Linphone/Chat/ChatReplyMessage.qml b/linphone-app/ui/modules/Linphone/Chat/ChatReplyMessage.qml index a477aaa82..e6114afc3 100644 --- a/linphone-app/ui/modules/Linphone/Chat/ChatReplyMessage.qml +++ b/linphone-app/ui/modules/Linphone/Chat/ChatReplyMessage.qml @@ -23,16 +23,18 @@ Item { id: mainItem property ChatMessageModel chatMessageModel property ChatMessageModel mainChatMessageModel - property int maxWidth : parent.width + property int availableWidth : parent.width property int headerHeight: ChatReplyMessageStyle.header.replyIcon.iconSize - property int replyHeight: (chatMessageModel ? replyMessage.height + usernameReplied.implicitHeight + ChatStyle.entry.message.padding * 3 + 3 : 0) - property int fitWidth: visible ? Math.max(usernameReplied.implicitWidth + replyMessage.fitWidth , headerArea.fitWidth) + 7 + ChatReplyMessageStyle.padding * 2 : 0 + //property int replyHeight: (chatMessageModel ? replyMessage.height + usernameReplied.implicitHeight + ChatStyle.entry.message.padding * 3 + 3 : 0) + //property int fitWidth: visible ? Math.max(usernameReplied.implicitWidth + replyMessage.fitWidth , headerArea.fitWidth) + 7 + ChatReplyMessageStyle.padding * 2 : 0 + property int replyHeight: (chatMessageModel ? chatContent.height + usernameReplied.implicitHeight + ChatStyle.entry.message.padding * 3 + 3 : 0) + property int fitWidth: visible ? Math.max(usernameReplied.implicitWidth, chatContent.bestWidth , headerArea.fitWidth) + 7 + ChatReplyMessageStyle.padding * 2 : 0 property int fitHeight: visible ? headerHeight + replyHeight : 0 property font customFont : SettingsModel.textMessageFont visible: mainChatMessageModel && mainChatMessageModel.isReply - width: maxWidth < 0 || maxWidth > fitWidth ? fitWidth : maxWidth + width: availableWidth < 0 || availableWidth > fitWidth ? fitWidth : availableWidth height: fitHeight onMainChatMessageModelChanged: if( mainChatMessageModel && mainChatMessageModel.replyChatMessageModel) chatMessageModel = mainChatMessageModel.replyChatMessageModel @@ -80,15 +82,25 @@ Item { Layout.bottomMargin: ChatStyle.entry.message.padding Layout.leftMargin: 10 Layout.rightMargin: 10 + clip: true Rectangle{ + id: colorBar anchors.left: parent.left anchors.top: parent.top anchors.bottom: parent.bottom - width: 7 + width: 15 + radius: 8 color: chatMessageModel && chatMessageModel.isOutgoing ? ChatReplyMessageStyle.replyArea.outgoingMarkColor.color : ChatReplyMessageStyle.replyArea.incomingMarkColor.color + Rectangle{ + anchors.right: parent.right + anchors.top: parent.top + anchors.bottom: parent.bottom + width: 5 + color: ChatReplyMessageStyle.replyArea.backgroundColor.color + } } - radius: 5 + radius: 8 color: ChatReplyMessageStyle.replyArea.backgroundColor.color visible: chatMessageModel != undefined Text{ @@ -98,7 +110,6 @@ Item { anchors.right: parent.right anchors.topMargin: 3 - leftPadding: 2 * ChatStyle.entry.message.padding text: mainChatMessageModel && mainChatMessageModel.fromDisplayNameReplyMessage @@ -108,48 +119,20 @@ Item { color: ChatReplyMessageStyle.replyArea.foregroundColor.color } - ScrollableListView { - id: replyMessage - property int fitWidth : 0 - hideScrollBars: true + ChatContent{ + id: chatContent anchors.top: usernameReplied.bottom - anchors.left: parent.left + chatMessageModel: mainItem.chatMessageModel + availableWidth: mainItem.availableWidth + anchors.left: colorBar.right anchors.right: parent.right anchors.topMargin: 3 - anchors.leftMargin: 5 - interactive: false - clip: false + useTextColor: true + textColor: ChatReplyMessageStyle.replyArea.foregroundColor.color - function updateWidth(){ - var maxWidth = 0 - for(var child in replyMessage.contentItem.children) { - var a = replyMessage.contentItem.children[child].fitWidth - if(a) - maxWidth = Math.max(maxWidth,a) - } - fitWidth = maxWidth - } - - model: ContentProxyModel{ - chatMessageModel: mainItem.chatMessageModel - } - - onContentHeightChanged: Qt.callLater( function(){replyMessage.height = replyMessage.contentHeight}) - - delegate: ChatContent{ - contentModel: $modelData - textColor: ChatReplyMessageStyle.replyArea.foregroundColor.color - onFitWidthChanged:{ - replyMessage.updateWidth() - } - Rectangle{ - anchors.left: parent.left - anchors.right: parent.right - color: ChatStyle.entry.separator.colorModel.color - height: visible ? ChatStyle.entry.separator.width : 0 - visible: (index !== (replyMessage.count - 1)) - } - } + fileBackgroundRadius:5 + fileBackgroundColor: ChatReplyMessageStyle.replyArea.fileBackgroundColor.color + fileBorderWidth:1 } } } diff --git a/linphone-app/ui/modules/Linphone/Chat/ChatReplyPreview.qml b/linphone-app/ui/modules/Linphone/Chat/ChatReplyPreview.qml index 2999d1327..8ce8e186f 100644 --- a/linphone-app/ui/modules/Linphone/Chat/ChatReplyPreview.qml +++ b/linphone-app/ui/modules/Linphone/Chat/ChatReplyPreview.qml @@ -17,8 +17,9 @@ import 'Chat.js' as Logic Rectangle{ id: replyPreviewBlock property ChatRoomModel chatRoomModel + property ChatMessageModel replyModel: chatRoomModel ? chatRoomModel.reply : null property int maxHeight : parent.maxHeight - Layout.preferredHeight: visible ? Math.min(messageContentsList.height + replyPreviewHeaderArea.implicitHeight + 15, replyPreviewBlock.maxHeight) : 0 + Layout.preferredHeight: visible ? Math.min(messageContents.height + replyPreviewHeaderArea.implicitHeight + 15, replyPreviewBlock.maxHeight) : 0 property int leftMargin: 10 property int rightMargin: 10 @@ -71,33 +72,19 @@ Rectangle{ Flickable { id: replyPreviewTextArea - ScrollBar.vertical: ForceScrollBar {visible: replyPreviewTextArea.height < messageContentsList.height} + ScrollBar.vertical: ForceScrollBar {visible: replyPreviewTextArea.height < messageContents.height} boundsBehavior: Flickable.StopAtBounds - contentHeight: messageContentsList.height + contentHeight: messageContents.height contentWidth: width - ScrollBar.vertical.width flickableDirection: Flickable.VerticalFlick clip: true Layout.fillHeight: true Layout.fillWidth: true - ListView { - id: messageContentsList - anchors.left: parent.left - anchors.right: parent.right - model: ContentProxyModel{ - chatMessageModel: replyPreviewBlock.chatRoomModel && replyPreviewBlock.chatRoomModel.reply - } - height: contentHeight - clip: true - delegate: ChatContent{ - contentModel: $modelData - Rectangle{ - anchors.left: parent.left - anchors.right: parent.right - color: ChatStyle.entry.separator.colorModel.color - height: visible ? ChatStyle.entry.separator.width : 0 - visible: (index !== (messageContentsList.count - 1)) - } - } + ChatContent{ + id: messageContents + width: replyPreviewTextArea.contentWidth + chatMessageModel: replyPreviewBlock.replyModel + availableWidth: parent.width } } } diff --git a/linphone-app/ui/modules/Linphone/Chat/ChatTextMessage.qml b/linphone-app/ui/modules/Linphone/Chat/ChatTextMessage.qml index 2db19344d..3c179ccc8 100644 --- a/linphone-app/ui/modules/Linphone/Chat/ChatTextMessage.qml +++ b/linphone-app/ui/modules/Linphone/Chat/ChatTextMessage.qml @@ -23,8 +23,8 @@ TextEdit { property ContentModel contentModel property string lastTextSelected : '' property font customFont : SettingsModel.textMessageFont - property int fitHeight: visible ? contentHeight + padding + 8 : 0 - property int fitWidth: visible ? implicitWidth + 2: 0 // add 2 because there is a bug on border that lead to not fit text exactly + property int fitHeight: contentHeight + padding + 8 + property int fitWidth: implicitWidth + 2 // add 2 because there is a bug on border that lead to not fit text exactly signal rightClicked() @@ -32,8 +32,8 @@ TextEdit { property int removeWarningFromBindingLoop : implicitWidth // Just a dummy variable to remove meaningless binding loop on implicitWidth height: fitHeight - width: parent.width - visible: contentModel && contentModel.isText() + width: parent && parent.width || 1 + visible: contentModel// && contentModel.isText() clip: false padding: ChatStyle.entry.message.padding textMargin: 0 diff --git a/linphone-app/ui/modules/Linphone/Chat/Event.qml b/linphone-app/ui/modules/Linphone/Chat/Event.qml index b56de58a6..bdab26917 100644 --- a/linphone-app/ui/modules/Linphone/Chat/Event.qml +++ b/linphone-app/ui/modules/Linphone/Chat/Event.qml @@ -12,6 +12,9 @@ Row { id: mainItem property QtObject iconData property string translation + property bool isHovering : false + property bool isTopGrouped: false + property bool isBottomGrouped: false Component.onCompleted: { if ($chatEntry.status == LinphoneEnums.CallStatusSuccess) { if(!$chatEntry.isStart){ diff --git a/linphone-app/ui/modules/Linphone/Chat/IncomingMessage.qml b/linphone-app/ui/modules/Linphone/Chat/IncomingMessage.qml index 7fb191bd8..da2222cfd 100644 --- a/linphone-app/ui/modules/Linphone/Chat/IncomingMessage.qml +++ b/linphone-app/ui/modules/Linphone/Chat/IncomingMessage.qml @@ -12,6 +12,10 @@ RowLayout { Layout.fillWidth: true + property alias isHovering: message.isHovering + property alias isTopGrouped: message.isTopGrouped + property alias isBottomGrouped: message.isBottomGrouped + signal copyAllDone() signal copySelectionDone() signal replyClicked() @@ -66,16 +70,17 @@ RowLayout { Message { id: message - onCopyAllDone: parent.copyAllDone() - onCopySelectionDone: parent.copySelectionDone() - onReplyClicked: parent.replyClicked() - onForwardClicked: parent.forwardClicked() - onGoToMessage: parent.goToMessage(message) - onConferenceIcsCopied: parent.conferenceIcsCopied() - onAddContactClicked: parent.addContactClicked(contactAddress) - onViewContactClicked: parent.viewContactClicked(contactAddress) + onCopyAllDone: mainRow.copyAllDone() + onCopySelectionDone: mainRow.copySelectionDone() + onReplyClicked: mainRow.replyClicked() + onForwardClicked: mainRow.forwardClicked() + onGoToMessage: mainRow.goToMessage(message) + onConferenceIcsCopied: mainRow.conferenceIcsCopied() + onAddContactClicked: mainRow.addContactClicked(contactAddress) + onViewContactClicked: mainRow.viewContactClicked(contactAddress) Layout.fillWidth: true + Layout.rightMargin: 10 // Not a style. Workaround to avoid a 0 width. // Arbitrary value. diff --git a/linphone-app/ui/modules/Linphone/Chat/Message.qml b/linphone-app/ui/modules/Linphone/Chat/Message.qml index 2903361f0..1b7f3f3f9 100644 --- a/linphone-app/ui/modules/Linphone/Chat/Message.qml +++ b/linphone-app/ui/modules/Linphone/Chat/Message.qml @@ -1,5 +1,6 @@ import QtQuick 2.7 import QtQuick.Layouts 1.3 +import QtQml.Models 2.15 import Clipboard 1.0 import Common 1.0 @@ -16,6 +17,7 @@ import LinphoneEnums 1.0 import ColorsList 1.0 import 'Message.js' as Logic +import 'qrc:/ui/scripts/Utils/utils.js' as Utils // ============================================================================= @@ -25,8 +27,10 @@ Item { // --------------------------------------------------------------------------- property alias backgroundColorModel: rectangle.colorModel - + property bool isHovering : false default property alias _content: content.data + property bool isTopGrouped: false + property bool isBottomGrouped: false // --------------------------------------------------------------------------- @@ -41,94 +45,52 @@ Item { // --------------------------------------------------------------------------- property string lastTextSelected - implicitHeight: (deliveryLayout.visible? deliveryLayout.height : 0) +(ephemeralTimerRow.visible? 16 : 0) + messageData.height - + implicitHeight: (deliveryLayout.visible? deliveryLayout.height : 0) +(ephemeralTimerRow.visible? 16 : 0) + chatContent.height Rectangle { id: rectangle - property int maxWidth: parent.width - property int dataWidth: maxWidth + property int availableWidth: parent.width property bool ephemeral : $chatEntry.isEphemeral property var colorModel:{'color': 'transparent'} - function updateWidth(){ - var maxWidth = Math.max(forwardMessage.fitWidth, replyMessage.fitWidth) - for(var child in messageContentsList.contentItem.children) { - var a = messageContentsList.contentItem.children[child].fitWidth - if(a) - maxWidth = Math.max(maxWidth,a) - } - rectangle.dataWidth = maxWidth - } + + anchors.left: !$chatEntry.isOutgoing ? parent.left : undefined + anchors.right: $chatEntry.isOutgoing ? parent.right : undefined + height: parent.height - (deliveryLayout.visible? deliveryLayout.height : 0) radius: ChatStyle.entry.message.radius clip: false color: colorModel.color - width: ( - ephemeralTimerRow.visible && dataWidth < ephemeralTimerRow.width + 2*ChatStyle.entry.message.padding + width: (//implicitWidth + ephemeralTimerRow.visible && (chatContent.bestWidth < ephemeralTimerRow.width + 2*ChatStyle.entry.message.padding) ? ephemeralTimerRow.width + 2*ChatStyle.entry.message.padding - : Math.min(dataWidth, maxWidth) + : Math.min(chatContent.bestWidth, availableWidth) ) + // --------------------------------------------------------------------------- // Message. // --------------------------------------------------------------------------- - - Column{ - id: messageData + Rectangle{ + visible: container.isTopGrouped || container.isBottomGrouped + color: parent.color + anchors.left: !$chatEntry.isOutgoing ? parent.left : undefined + anchors.right: $chatEntry.isOutgoing ? parent.right : undefined + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.topMargin: container.isTopGrouped ? 0 : parent.radius + anchors.bottomMargin: container.isBottomGrouped ? 0 : parent.radius + width: parent.radius + } + ChatFullContent{ + id: chatContent + anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right - spacing: 0 - ChatForwardMessage{ - id: forwardMessage - mainChatMessageModel: $chatEntry - visible: $chatEntry.isForward - maxWidth: container.width - onFitWidthChanged:{ - rectangle.updateWidth() - } - } - ChatReplyMessage{ - id: replyMessage - z: 1 - mainChatMessageModel: $chatEntry - visible: $chatEntry.isReply - maxWidth: container.width - onFitWidthChanged:{ - rectangle.updateWidth() - } - onGoToMessage: container.goToMessage(message) - } - ListView { - id: messageContentsList - anchors.left: parent.left - anchors.right: parent.right - visible: count > 0 - spacing: 0 - clip: false - model: ContentProxyModel{ - chatMessageModel: $chatEntry - } - height: contentHeight - boundsBehavior: Flickable.StopAtBounds - interactive: false - delegate: - ChatContent{ - maxWidth: container.width - contentModel: $modelData - onFitWidthChanged:{ - rectangle.updateWidth() - } - onLastTextSelectedChanged: container.lastTextSelected= lastTextSelected - onRightClicked: chatMenu.open() - onConferenceIcsCopied: container.conferenceIcsCopied() - onFileIsHoveringChanged: menuButton.visible = !fileIsHovering - Rectangle{ - anchors.left: parent.left - anchors.right: parent.right - color: ChatStyle.entry.separator.colorModel.color - height: visible ? ChatStyle.entry.separator.width : 0 - visible: (index !== (messageContentsList.count - 1)) - } - } - } + chatMessageModel: $chatEntry + availableWidth: rectangle.availableWidth + onLastTextSelectedChanged: container.lastTextSelected= lastTextSelected + onGoToMessage: container.goToMessage(message) + onRightClicked: chatMenu.open() + onConferenceIcsCopied: container.conferenceIcsCopied() + onIsFileHoveringChanged: menuButton.visible = !isFileHovering } Row{ id:ephemeralTimerRow @@ -158,7 +120,6 @@ Item { } } } - // --------------------------------------------------------------------------- // Extra content. // --------------------------------------------------------------------------- @@ -168,8 +129,10 @@ Item { anchors { left: rectangle.right + bottom: rectangle.bottom leftMargin: ChatStyle.entry.message.extraContent.leftMargin } + } ChatDeliveries{ id: deliveryLayout @@ -193,7 +156,7 @@ Item { backgroundRadius: 8 colorSet : ChatStyle.entry.menu - visible: isHoverEntry() + visible: container.isHovering onClicked: chatMenu.open() } diff --git a/linphone-app/ui/modules/Linphone/Chat/Notice.qml b/linphone-app/ui/modules/Linphone/Chat/Notice.qml index 2a0e845f3..d3a48080f 100644 --- a/linphone-app/ui/modules/Linphone/Chat/Notice.qml +++ b/linphone-app/ui/modules/Linphone/Chat/Notice.qml @@ -95,6 +95,9 @@ RowLayout{ property color eventColor : (isError ? ChatStyle.entry.event.notice.errorColor.color : ( isImportant ? ChatStyle.entry.event.notice.importantColor.color : ChatStyle.entry.event.notice.colorModel.color )) + property bool isHovering : false + property bool isTopGrouped: false + property bool isBottomGrouped: false Layout.preferredHeight: ChatStyle.entry.lineHeight spacing: ChatStyle.entry.message.extraContent.spacing diff --git a/linphone-app/ui/modules/Linphone/Chat/OutgoingMessage.qml b/linphone-app/ui/modules/Linphone/Chat/OutgoingMessage.qml index 7d33d5ada..5b04ca996 100644 --- a/linphone-app/ui/modules/Linphone/Chat/OutgoingMessage.qml +++ b/linphone-app/ui/modules/Linphone/Chat/OutgoingMessage.qml @@ -11,9 +11,15 @@ import Utils 1.0 // ============================================================================= Item { + id: mainItem implicitHeight: message.height //width: parent.width Layout.fillWidth: true + //onWidthChanged: console.log(width) + + property alias isHovering: message.isHovering + property alias isTopGrouped: message.isTopGrouped + property alias isBottomGrouped: message.isBottomGrouped signal copyAllDone() signal copySelectionDone() @@ -23,64 +29,91 @@ Item { signal conferenceIcsCopied() signal addContactClicked(string contactAddress) signal viewContactClicked(string contactAddress) - - Message { - id: message - - onCopyAllDone: parent.copyAllDone() - onCopySelectionDone: parent.copySelectionDone() - onReplyClicked: parent.replyClicked() - onForwardClicked: parent.forwardClicked() - onGoToMessage: parent.goToMessage(message) - onConferenceIcsCopied: parent.conferenceIcsCopied() - onAddContactClicked: parent.addContactClicked(contactAddress) - onViewContactClicked: parent.viewContactClicked(contactAddress) - + RowLayout{ + /* anchors { - left: parent.left - leftMargin: ChatStyle.entry.metaWidth - right: parent.right + left: parent.left + //leftMargin: ChatStyle.entry.metaWidth + right: parent.right + } + */ + //width: parent.width + anchors.fill: parent + //onWidthChanged: console.log(width) + spacing: 0 + //spacing: ChatStyle.entry.message.extraContent.spacing + Message { + id: message + + onCopyAllDone: mainItem.copyAllDone() + onCopySelectionDone: mainItem.copySelectionDone() + onReplyClicked: mainItem.replyClicked() + onForwardClicked: mainItem.forwardClicked() + onGoToMessage: mainItem.goToMessage(message) + onConferenceIcsCopied: mainItem.conferenceIcsCopied() + onAddContactClicked: mainItem.addContactClicked(contactAddress) + onViewContactClicked: mainItem.viewContactClicked(contactAddress) + /* + anchors { + left: parent.left + leftMargin: ChatStyle.entry.metaWidth + right: parent.right + }*/ + backgroundColorModel: ChatStyle.entry.message.outgoing.backgroundColor + Layout.fillWidth: true + //Layout.fillHeight: true + Layout.leftMargin: 10 + //onImplicitHeightChanged: Layout.preferredHeight= implicitHeight + Layout.minimumHeight: implicitHeight // Avoid bug where UI is not computed by Qt + Layout.preferredHeight: implicitHeight + //Layout.preferredWidth: parent.width + //width: parent.width + // Not a style. Workaround to avoid a 0 width. + // Arbitrary value. + Layout.minimumWidth: 1 + //onWidthChanged: console.log(width) + } - backgroundColorModel: ChatStyle.entry.message.outgoing.backgroundColor - width: parent.width - - Row { + /* + RowLayout { anchors.fill: parent anchors.leftMargin: ChatStyle.entry.message.extraContent.leftMargin spacing: ChatStyle.entry.message.extraContent.spacing - + */ Component { id: iconComponent - - Icon { - id: iconId - readonly property var isError: Utils.includes([ - LinphoneEnums.ChatMessageStateFileTransferError, - LinphoneEnums.ChatMessageStateNotDelivered, - ], $chatEntry.state) - readonly property bool isUploaded: $chatEntry.state == LinphoneEnums.ChatMessageStateDelivered - readonly property bool isDelivered: $chatEntry.state == LinphoneEnums.ChatMessageStateDeliveredToUser - readonly property bool isRead: $chatEntry.state == LinphoneEnums.ChatMessageStateDisplayed - - icon: iconId.isError - ? 'chat_error' - : (iconId.isRead ? 'chat_read' : (iconId.isDelivered ? 'chat_delivered' : '' ) ) - iconSize: ChatStyle.entry.message.outgoing.sendIconSize - - MouseArea { - id:retryAction - anchors.fill: parent - visible: iconId.isError || $chatEntry.state == LinphoneEnums.ChatMessageStateIdle - onClicked: $chatEntry.resendMessage() - } - - TooltipArea { - id:tooltip - visible: text != '' - text: iconId.isError - ? qsTr('messageError') - : (iconId.isRead ? qsTr('messageRead') : (isDelivered ? qsTr('messageDelivered') : '')) - hoveringCursor : retryAction.visible?Qt.PointingHandCursor:Qt.ArrowCursor + Item{ + Icon { + id: iconId + readonly property var isError: Utils.includes([ + LinphoneEnums.ChatMessageStateFileTransferError, + LinphoneEnums.ChatMessageStateNotDelivered, + ], $chatEntry.state) + readonly property bool isUploaded: $chatEntry.state == LinphoneEnums.ChatMessageStateDelivered + readonly property bool isDelivered: $chatEntry.state == LinphoneEnums.ChatMessageStateDeliveredToUser + readonly property bool isRead: $chatEntry.state == LinphoneEnums.ChatMessageStateDisplayed + + icon: iconId.isError + ? 'chat_error' + : (iconId.isRead ? 'chat_read' : (iconId.isDelivered ? 'chat_delivered' : '' ) ) + iconSize: ChatStyle.entry.message.outgoing.sendIconSize + anchors.bottom: parent.bottom + anchors.horizontalCenter: parent.horizontalCenter + MouseArea { + id:retryAction + anchors.fill: parent + visible: iconId.isError || $chatEntry.state == LinphoneEnums.ChatMessageStateIdle + onClicked: $chatEntry.resendMessage() + } + + TooltipArea { + id:tooltip + visible: text != '' + text: iconId.isError + ? qsTr('messageError') + : (iconId.isRead ? qsTr('messageRead') : (iconId.isDelivered ? qsTr('messageDelivered') : '')) + hoveringCursor : retryAction.visible?Qt.PointingHandCursor:Qt.ArrowCursor + } } } } @@ -89,8 +122,6 @@ Item { id: indicator Item { - anchors.fill: parent - BusyIndicator { anchors.centerIn: parent @@ -101,13 +132,23 @@ Item { } Loader { - height: ChatStyle.entry.lineHeight - width: ChatStyle.entry.message.outgoing.areaSize + //height: ChatStyle.entry.lineHeight + //anchors.bottom: parent.bottom + //Layout.alignment: Qt.AlignBottom | Qt.AlignHCenter + Layout.preferredWidth: ChatStyle.entry.message.outgoing.areaSize + Layout.fillHeight: true + //Layout.rightMargin: 10 sourceComponent: $chatEntry.state == LinphoneEnums.ChatMessageStateInProgress || $chatEntry.state == LinphoneEnums.ChatMessageStateFileTransferInProgress ? indicator : iconComponent } - } + //} } + /* + Rectangle{ + anchors.fill: parent + color: 'yellow' + } + */ } diff --git a/linphone-app/ui/modules/Linphone/Contact/ContactDescription.qml b/linphone-app/ui/modules/Linphone/Contact/ContactDescription.qml index 8b515724e..bd944a223 100644 --- a/linphone-app/ui/modules/Linphone/Contact/ContactDescription.qml +++ b/linphone-app/ui/modules/Linphone/Contact/ContactDescription.qml @@ -76,12 +76,7 @@ Column { } Text{ id:status - Layout.fillWidth: true Layout.alignment: Qt.AlignVCenter - //anchors.top:parent.top - //anchors.bottom : parent.bottom - //anchors.left:parent.right - //anchors.leftMargin:5 verticalAlignment: Text.AlignVCenter visible: text != '' text : '' diff --git a/linphone-app/ui/modules/Linphone/Styles/Chat/ChatReplyMessageStyle.qml b/linphone-app/ui/modules/Linphone/Styles/Chat/ChatReplyMessageStyle.qml index da4dae88e..b4ff711d8 100644 --- a/linphone-app/ui/modules/Linphone/Styles/Chat/ChatReplyMessageStyle.qml +++ b/linphone-app/ui/modules/Linphone/Styles/Chat/ChatReplyMessageStyle.qml @@ -18,12 +18,14 @@ QtObject { } } property QtObject replyArea: QtObject{ - property var outgoingMarkColor: ColorsList.add(sectionName+'_reply_outgoing_mark', 'm') - property var incomingMarkColor: ColorsList.add(sectionName+'_reply_incoming_mark', 'r') + property var outgoingMarkColor: ColorsList.add(sectionName+'_reply_outgoing_mark', 'outgoing_reply_mark_bg') + property var incomingMarkColor: ColorsList.add(sectionName+'_reply_incoming_mark', 'incoming_reply_mark_bg') property var backgroundColor: ColorsList.add(sectionName+'_reply_bg', 'q') property var foregroundColor: ColorsList.add(sectionName+'_reply_fg', 'h') + property var fileBackgroundColor: ColorsList.add(sectionName+'_reply_file_bg', 'reply_file_bg') property int usernamePointSizeOffset: -2 property int pointSizeOffset: -2 + } property int padding: 8 diff --git a/linphone-app/ui/modules/Linphone/Styles/Chat/ChatStyle.qml b/linphone-app/ui/modules/Linphone/Styles/Chat/ChatStyle.qml index 2c6a5b814..b363eab10 100644 --- a/linphone-app/ui/modules/Linphone/Styles/Chat/ChatStyle.qml +++ b/linphone-app/ui/modules/Linphone/Styles/Chat/ChatStyle.qml @@ -173,7 +173,7 @@ QtObject { property QtObject message: QtObject { property int padding: 8 - property int radius: 4 + property int radius: 8 property QtObject extraContent: QtObject { property int leftMargin: 10 @@ -182,7 +182,7 @@ QtObject { } property QtObject file: QtObject { - property int height: 80 + property int height: 120 property int heightbetter: 200 property int iconSize: 18 property int margins: 8 @@ -212,10 +212,11 @@ QtObject { property string icon: 'file_extension_custom' property string unknownIcon: 'file_unknown_custom' property int iconSize: 60 - property int radius: 5 + property int radius: 0 property QtObject background: QtObject { property var colorModel: ColorsList.add(sectionName+'_file_extension_bg', 'q') + property var borderColorModel: ColorsList.add(sectionName+'_file_extension_border', 'extension_file_border') } property QtObject text: QtObject { @@ -249,7 +250,7 @@ QtObject { property QtObject incoming: QtObject { property var backgroundColor: ColorsList.add(sectionName+'_incoming_bg', 'incoming_bg') - property int avatarSize: 20 + property int avatarSize: 30 property QtObject text: QtObject { property var colorModel: ColorsList.add(sectionName+'_incoming_text', 'd') @@ -259,9 +260,9 @@ QtObject { property QtObject outgoing: QtObject { property var backgroundColor: ColorsList.add(sectionName+'_outgoing_bg', 'outgoing_bg') - property int areaSize: 12 + property int areaSize: 32 property int busyIndicatorSize: 12 - property int sendIconSize: 60 + property int sendIconSize: 12 property QtObject text: QtObject { property var colorModel: ColorsList.add(sectionName+'_outgoing_text', 'd') diff --git a/linphone-app/ui/modules/Linphone/qmldir b/linphone-app/ui/modules/Linphone/qmldir index 6953676c1..1a289dc89 100644 --- a/linphone-app/ui/modules/Linphone/qmldir +++ b/linphone-app/ui/modules/Linphone/qmldir @@ -18,11 +18,14 @@ IncallAvatar 1.0 Calls/IncallAvatar.qml CameraItem 1.0 Camera/CameraItem.qml CameraView 1.0 Camera/CameraView.qml + Chat 1.0 Chat/Chat.qml ChatAudioMessage 1.0 Chat/ChatAudioMessage.qml ChatAudioPreview 1.0 Chat/ChatAudioPreview.qml ChatCalendarMessage 1.0 Chat/ChatCalendarMessage.qml ChatConferenceInvitationMessage 1.0 Chat/ChatConferenceInvitationMessage.qml +ChatContent 1.0 Chat/ChatContent.qml +ChatFullContent 1.0 Chat/ChatFullContent.qml ChatMessagePreview 1.0 Chat/ChatMessagePreview.qml ChatForwardMessage 1.0 Chat/ChatForwardMessage.qml ChatReplyMessage 1.0 Chat/ChatReplyMessage.qml diff --git a/linphone-app/ui/scripts/Utils/utils.js b/linphone-app/ui/scripts/Utils/utils.js index 698b25b5b..83c3a7042 100644 --- a/linphone-app/ui/scripts/Utils/utils.js +++ b/linphone-app/ui/scripts/Utils/utils.js @@ -722,5 +722,8 @@ function printObject(o) { for (var p in o) { out += p + ': ' + o[p] + '\n'; } - return out; + if(!o) + return 'Empty' + else + return out; }