mirror of
https://gitlab.linphone.org/BC/public/linphone-desktop.git
synced 2026-01-17 11:28:07 +00:00
Upgrade search and message loading. More smart loading entries based on currently view.
Add a spinner while loading/searching.
This commit is contained in:
parent
d6ca4b1ab8
commit
99b9a7753c
7 changed files with 350 additions and 310 deletions
|
|
@ -47,7 +47,7 @@ if(WIN32)
|
|||
endif()
|
||||
elseif( APPLE )
|
||||
if( NOT CMAKE_OSX_DEPLOYMENT_TARGET)
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.9")
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.9" CACHE STRING "Minimum OS X deployment version")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
|
|
|||
|
|
@ -773,7 +773,7 @@ void ChatRoomModel::initEntries(){
|
|||
}
|
||||
}
|
||||
|
||||
void ChatRoomModel::loadMoreEntries(){
|
||||
int ChatRoomModel::loadMoreEntries(){
|
||||
QList<std::shared_ptr<ChatEvent> > entries;
|
||||
QList<EntrySorterHelper> prepareEntries;
|
||||
// Get current event count for each type
|
||||
|
|
@ -838,6 +838,7 @@ void ChatRoomModel::loadMoreEntries(){
|
|||
emit layoutChanged();
|
||||
updateLastUpdateTime();
|
||||
}
|
||||
return entries.size();
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -218,7 +218,7 @@ public:
|
|||
void compose ();
|
||||
void resetMessageCount ();
|
||||
Q_INVOKABLE void initEntries();
|
||||
Q_INVOKABLE void loadMoreEntries();
|
||||
Q_INVOKABLE int loadMoreEntries(); // return new entries count
|
||||
void callEnded(std::shared_ptr<linphone::Call> call);
|
||||
|
||||
QDateTime mLastUpdateTime;
|
||||
|
|
|
|||
|
|
@ -140,17 +140,14 @@ void ChatRoomProxyModel::compose (const QString& text) {
|
|||
|
||||
void ChatRoomProxyModel::loadMoreEntries () {
|
||||
if(mChatRoomModel ) {
|
||||
int count = rowCount();
|
||||
int parentCount = sourceModel()->rowCount();
|
||||
if (count == mMaxDisplayedEntries)
|
||||
mMaxDisplayedEntries += EntriesChunkSize;
|
||||
|
||||
if (count + 10 >= parentCount) // Magic number : try to load more entries if near to max event count
|
||||
mChatRoomModel->loadMoreEntries();
|
||||
invalidateFilter();
|
||||
count = rowCount() - count;
|
||||
if (count > 0)
|
||||
emit moreEntriesLoaded(count);
|
||||
int currentRowCount = rowCount();
|
||||
int newEntries = 0;
|
||||
do{
|
||||
newEntries = mChatRoomModel->loadMoreEntries();
|
||||
invalidate();
|
||||
}while( newEntries>0 && currentRowCount == rowCount());
|
||||
currentRowCount = rowCount() - currentRowCount + 1;
|
||||
emit moreEntriesLoaded(currentRowCount);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -262,7 +259,6 @@ QString ChatRoomProxyModel::getCachedText() const{
|
|||
// -----------------------------------------------------------------------------
|
||||
|
||||
void ChatRoomProxyModel::reload (ChatRoomModel *chatRoomModel) {
|
||||
mMaxDisplayedEntries = EntriesChunkSize;
|
||||
|
||||
if (mChatRoomModel) {
|
||||
ChatRoomModel *ChatRoomModel = mChatRoomModel.get();
|
||||
|
|
@ -294,8 +290,13 @@ void ChatRoomProxyModel::resetMessageCount(){
|
|||
void ChatRoomProxyModel::setFilterText(const QString& text){
|
||||
if( mFilterText != text){
|
||||
mFilterText = text;
|
||||
invalidate();
|
||||
emit filterTextChanged();
|
||||
int currentRowCount = rowCount();
|
||||
int newEntries = 0;
|
||||
do{
|
||||
newEntries = mChatRoomModel->loadMoreEntries();
|
||||
invalidate();
|
||||
emit filterTextChanged();
|
||||
}while( newEntries>0 && currentRowCount == rowCount());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -336,7 +337,6 @@ void ChatRoomProxyModel::handleIsRemoteComposingChanged () {
|
|||
}
|
||||
|
||||
void ChatRoomProxyModel::handleMessageReceived (const shared_ptr<linphone::ChatMessage> &) {
|
||||
mMaxDisplayedEntries++;
|
||||
|
||||
QWindow *window = getParentWindow(this);
|
||||
if (window && window->isActive())
|
||||
|
|
@ -344,5 +344,4 @@ void ChatRoomProxyModel::handleMessageReceived (const shared_ptr<linphone::ChatM
|
|||
}
|
||||
|
||||
void ChatRoomProxyModel::handleMessageSent (const shared_ptr<linphone::ChatMessage> &) {
|
||||
mMaxDisplayedEntries++;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,14 +34,6 @@ function initView () {
|
|||
chat.bindToEnd = true
|
||||
}
|
||||
|
||||
function loadMoreEntries () {
|
||||
if (chat.atYBeginning && !chat.tryToLoadMoreEntries) {
|
||||
chat.tryToLoadMoreEntries = true
|
||||
chat.positionViewAtBeginning()
|
||||
container.proxyModel.loadMoreEntries()
|
||||
}
|
||||
}
|
||||
|
||||
function getComponentFromEntry (chatEntry) {
|
||||
if (chatEntry.fileContentModel && chatEntry.fileContentModel.name) {
|
||||
return 'FileMessage.qml'
|
||||
|
|
@ -77,7 +69,6 @@ function handleFilesDropped (files) {
|
|||
|
||||
function handleMoreEntriesLoaded (n) {
|
||||
chat.positionViewAtIndex(n - 1, QtQuick.ListView.Beginning)
|
||||
chat.tryToLoadMoreEntries = false
|
||||
}
|
||||
|
||||
function handleMovementEnded () {
|
||||
|
|
|
|||
|
|
@ -11,292 +11,330 @@ import 'Chat.js' as Logic
|
|||
// =============================================================================
|
||||
|
||||
Rectangle {
|
||||
id: container
|
||||
|
||||
property alias proxyModel: chat.model // ChatRoomProxyModel
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
signal messageToSend (string text)
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
color: ChatStyle.color
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
spacing: 0
|
||||
|
||||
ScrollableListView {
|
||||
id: chat
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
property bool bindToEnd: false
|
||||
property bool tryToLoadMoreEntries: true
|
||||
//property var sipAddressObserver: SipAddressesModel.getSipAddressObserver(proxyModel.fullPeerAddress, proxyModel.fullLocalAddress)
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
|
||||
highlightFollowsCurrentItem: false
|
||||
|
||||
section {
|
||||
criteria: ViewSection.FullString
|
||||
delegate: sectionHeading
|
||||
property: '$sectionDate'
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
Component.onCompleted: Logic.initView()
|
||||
|
||||
onContentYChanged: Logic.loadMoreEntries()
|
||||
onMovementEnded: Logic.handleMovementEnded()
|
||||
onMovementStarted: Logic.handleMovementStarted()
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
Connections {
|
||||
target: proxyModel
|
||||
|
||||
// When the view is changed (for example `Calls` -> `Messages`),
|
||||
// the position is set at end and it can be possible to load
|
||||
// more entries.
|
||||
onEntryTypeFilterChanged: Logic.initView()
|
||||
onMoreEntriesLoaded: Logic.handleMoreEntriesLoaded(n)
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Heading.
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
Component {
|
||||
id: sectionHeading
|
||||
|
||||
Item {
|
||||
implicitHeight: container.height + ChatStyle.sectionHeading.bottomMargin
|
||||
width: parent.width
|
||||
|
||||
Borders {
|
||||
id: container
|
||||
|
||||
borderColor: ChatStyle.sectionHeading.border.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.color
|
||||
font {
|
||||
bold: true
|
||||
pointSize: ChatStyle.sectionHeading.text.pointSize
|
||||
}
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
|
||||
// Cast section to integer because Qt converts the
|
||||
// sectionDate in string!!!
|
||||
text: new Date(section).toLocaleDateString(
|
||||
Qt.locale(App.locale)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Message/Event renderer.
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
delegate: Rectangle {
|
||||
id: entry
|
||||
property bool isNotice : $chatEntry.type === ChatRoomModel.NoticeEntry
|
||||
property bool isCall : $chatEntry.type === ChatRoomModel.CallEntry
|
||||
property bool isMessage : $chatEntry.type === ChatRoomModel.MessageEntry
|
||||
|
||||
function isHoverEntry () {
|
||||
return mouseArea.containsMouse
|
||||
}
|
||||
|
||||
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.color
|
||||
implicitHeight: layout.height + ChatStyle.entry.bottomMargin
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
|
||||
cursorShape: Qt.ArrowCursor
|
||||
hoverEnabled: true
|
||||
implicitHeight: layout.height
|
||||
width: parent.width + parent.anchors.rightMargin
|
||||
acceptedButtons: Qt.NoButton
|
||||
ColumnLayout{
|
||||
id: layout
|
||||
spacing: 0
|
||||
width: entry.width
|
||||
Text{
|
||||
id:authorName
|
||||
Layout.leftMargin: timeDisplay.width + 10
|
||||
Layout.fillWidth: true
|
||||
text : $chatEntry.fromDisplayName ? $chatEntry.fromDisplayName : ''
|
||||
property var previousItem : {
|
||||
if(index >0)
|
||||
return proxyModel.getAt(index-1)
|
||||
else
|
||||
return null
|
||||
}
|
||||
id: container
|
||||
|
||||
property alias proxyModel: chat.model // ChatRoomProxyModel
|
||||
property alias tryingToLoadMoreEntries : chat.tryToLoadMoreEntries
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
signal messageToSend (string text)
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
color: ChatStyle.color
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
spacing: 0
|
||||
|
||||
ScrollableListView {
|
||||
id: chat
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
property bool bindToEnd: false
|
||||
property bool tryToLoadMoreEntries: true
|
||||
//property var sipAddressObserver: SipAddressesModel.getSipAddressObserver(proxyModel.fullPeerAddress, proxyModel.fullLocalAddress)
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
|
||||
highlightFollowsCurrentItem: false
|
||||
|
||||
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()
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
Connections {
|
||||
target: proxyModel
|
||||
|
||||
// When the view is changed (for example `Calls` -> `Messages`),
|
||||
// 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
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Heading.
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
Component {
|
||||
id: sectionHeading
|
||||
|
||||
Item {
|
||||
implicitHeight: container.height + ChatStyle.sectionHeading.bottomMargin
|
||||
width: parent.width
|
||||
|
||||
color: ChatStyle.entry.event.text.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
|
||||
)
|
||||
Borders {
|
||||
id: container
|
||||
|
||||
borderColor: ChatStyle.sectionHeading.border.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.color
|
||||
font {
|
||||
bold: true
|
||||
pointSize: ChatStyle.sectionHeading.text.pointSize
|
||||
}
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
|
||||
// Cast section to integer because Qt converts the
|
||||
// sectionDate in string!!!
|
||||
text: new Date(section).toLocaleDateString(
|
||||
Qt.locale(App.locale)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
RowLayout {
|
||||
|
||||
spacing: 0
|
||||
width: entry.width
|
||||
|
||||
// Display time.
|
||||
Text {
|
||||
id:timeDisplay
|
||||
Layout.alignment: Qt.AlignTop
|
||||
Layout.preferredHeight: ChatStyle.entry.lineHeight
|
||||
Layout.preferredWidth: ChatStyle.entry.time.width
|
||||
|
||||
color: ChatStyle.entry.event.text.color
|
||||
font.pointSize: ChatStyle.entry.time.pointSize
|
||||
|
||||
text: $chatEntry.timestamp.toLocaleString(
|
||||
Qt.locale(App.locale),
|
||||
'hh:mm'
|
||||
)
|
||||
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
|
||||
TooltipArea {
|
||||
text: $chatEntry.timestamp.toLocaleString(Qt.locale(App.locale))
|
||||
}
|
||||
visible:!isNotice
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Message/Event renderer.
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
delegate: Rectangle {
|
||||
id: entry
|
||||
property bool isNotice : $chatEntry.type === ChatRoomModel.NoticeEntry
|
||||
property bool isCall : $chatEntry.type === ChatRoomModel.CallEntry
|
||||
property bool isMessage : $chatEntry.type === ChatRoomModel.MessageEntry
|
||||
|
||||
function isHoverEntry () {
|
||||
return mouseArea.containsMouse
|
||||
}
|
||||
|
||||
// Display content.
|
||||
Loader {
|
||||
Layout.fillWidth: true
|
||||
source: Logic.getComponentFromEntry($chatEntry)
|
||||
|
||||
function removeEntry () {
|
||||
proxyModel.removeRow(index)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
footer: Text {
|
||||
property var composers : container.proxyModel.composers
|
||||
color: ChatStyle.composingText.color
|
||||
font.pointSize: ChatStyle.composingText.pointSize
|
||||
height: visible ? undefined : 0
|
||||
leftPadding: ChatStyle.composingText.leftPadding
|
||||
visible: composers.length > 0 && SettingsModel.chatEnabled
|
||||
wrapMode: Text.Wrap
|
||||
//: '%1 is typing...' indicate that someone is composing in chat
|
||||
text:(composers.length==0?'': qsTr('chatTyping','',composers.length).arg(container.proxyModel.getDisplayNameComposers()))
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Send area.
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
Borders {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: textArea.height
|
||||
|
||||
borderColor: ChatStyle.sendArea.border.color
|
||||
topWidth: ChatStyle.sendArea.border.width
|
||||
visible: SettingsModel.chatEnabled && proxyModel.chatRoomModel && !proxyModel.chatRoomModel.hasBeenLeft
|
||||
|
||||
DroppableTextArea {
|
||||
id: textArea
|
||||
|
||||
enabled:proxyModel && proxyModel.chatRoomModel ? !proxyModel.chatRoomModel.hasBeenLeft:false
|
||||
isEphemeral : proxyModel && proxyModel.chatRoomModel ? proxyModel.chatRoomModel.ephemeralEnabled:false
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
|
||||
height:ChatStyle.sendArea.height + ChatStyle.sendArea.border.width
|
||||
minimumHeight:ChatStyle.sendArea.height + ChatStyle.sendArea.border.width
|
||||
maximumHeight:container.height/2
|
||||
|
||||
dropEnabled: SettingsModel.fileTransferUrl.length > 0
|
||||
dropDisabledReason: qsTr('noFileTransferUrl')
|
||||
placeholderText: qsTr('newMessagePlaceholder')
|
||||
|
||||
onDropped: Logic.handleFilesDropped(files)
|
||||
onTextChanged: Logic.handleTextChanged(text)
|
||||
onValidText: {
|
||||
textArea.text = ''
|
||||
chat.bindToEnd = true
|
||||
if(proxyModel.chatRoomModel)
|
||||
proxyModel.sendMessage(text)
|
||||
else{
|
||||
console.log("Peer : " +proxyModel.peerAddress+ "/"+chat.model.peerAddress)
|
||||
proxyModel.chatRoomModel = CallsListModel.createChat(proxyModel.peerAddress)
|
||||
proxyModel.sendMessage(text)
|
||||
|
||||
color: ChatStyle.color
|
||||
implicitHeight: layout.height + ChatStyle.entry.bottomMargin
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
|
||||
cursorShape: Qt.ArrowCursor
|
||||
hoverEnabled: true
|
||||
implicitHeight: layout.height
|
||||
width: parent.width + parent.anchors.rightMargin
|
||||
acceptedButtons: Qt.NoButton
|
||||
ColumnLayout{
|
||||
id: layout
|
||||
spacing: 0
|
||||
width: entry.width
|
||||
Text{
|
||||
id:authorName
|
||||
Layout.leftMargin: timeDisplay.width + 10
|
||||
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.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
|
||||
|
||||
// Display time.
|
||||
Text {
|
||||
id:timeDisplay
|
||||
Layout.alignment: Qt.AlignTop
|
||||
Layout.preferredHeight: ChatStyle.entry.lineHeight
|
||||
Layout.preferredWidth: ChatStyle.entry.time.width
|
||||
|
||||
color: ChatStyle.entry.event.text.color
|
||||
font.pointSize: ChatStyle.entry.time.pointSize
|
||||
|
||||
text: $chatEntry.timestamp.toLocaleString(
|
||||
Qt.locale(App.locale),
|
||||
'hh:mm'
|
||||
)
|
||||
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
|
||||
TooltipArea {
|
||||
text: $chatEntry.timestamp.toLocaleString(Qt.locale(App.locale))
|
||||
}
|
||||
visible:!isNotice
|
||||
}
|
||||
|
||||
// Display content.
|
||||
Loader {
|
||||
Layout.fillWidth: true
|
||||
source: Logic.getComponentFromEntry($chatEntry)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
footer: Text {
|
||||
property var composers : container.proxyModel.composers
|
||||
color: ChatStyle.composingText.color
|
||||
font.pointSize: ChatStyle.composingText.pointSize
|
||||
height: visible ? undefined : 0
|
||||
leftPadding: ChatStyle.composingText.leftPadding
|
||||
visible: composers.length > 0 && SettingsModel.chatEnabled
|
||||
wrapMode: Text.Wrap
|
||||
//: '%1 is typing...' indicate that someone is composing in chat
|
||||
text:(composers.length==0?'': qsTr('chatTyping','',composers.length).arg(container.proxyModel.getDisplayNameComposers()))
|
||||
}
|
||||
}
|
||||
Component.onCompleted: {text = proxyModel.cachedText; cursorPosition=text.length}
|
||||
Rectangle{
|
||||
anchors.fill:parent
|
||||
color:'white'
|
||||
opacity: 0.5
|
||||
visible:!textArea.enabled
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Send area.
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
Borders {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: textArea.height
|
||||
|
||||
borderColor: ChatStyle.sendArea.border.color
|
||||
topWidth: ChatStyle.sendArea.border.width
|
||||
visible: SettingsModel.chatEnabled && proxyModel.chatRoomModel && !proxyModel.chatRoomModel.hasBeenLeft
|
||||
|
||||
DroppableTextArea {
|
||||
id: textArea
|
||||
|
||||
enabled:proxyModel && proxyModel.chatRoomModel ? !proxyModel.chatRoomModel.hasBeenLeft:false
|
||||
isEphemeral : proxyModel && proxyModel.chatRoomModel ? proxyModel.chatRoomModel.ephemeralEnabled:false
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
|
||||
height:ChatStyle.sendArea.height + ChatStyle.sendArea.border.width
|
||||
minimumHeight:ChatStyle.sendArea.height + ChatStyle.sendArea.border.width
|
||||
maximumHeight:container.height/2
|
||||
|
||||
dropEnabled: SettingsModel.fileTransferUrl.length > 0
|
||||
dropDisabledReason: qsTr('noFileTransferUrl')
|
||||
placeholderText: qsTr('newMessagePlaceholder')
|
||||
|
||||
onDropped: Logic.handleFilesDropped(files)
|
||||
onTextChanged: Logic.handleTextChanged(text)
|
||||
onValidText: {
|
||||
textArea.text = ''
|
||||
chat.bindToEnd = true
|
||||
if(proxyModel.chatRoomModel)
|
||||
proxyModel.sendMessage(text)
|
||||
else{
|
||||
console.log("Peer : " +proxyModel.peerAddress+ "/"+chat.model.peerAddress)
|
||||
proxyModel.chatRoomModel = CallsListModel.createChat(proxyModel.peerAddress)
|
||||
proxyModel.sendMessage(text)
|
||||
}
|
||||
}
|
||||
Component.onCompleted: {text = proxyModel.cachedText; cursorPosition=text.length}
|
||||
Rectangle{
|
||||
anchors.fill:parent
|
||||
color:'white'
|
||||
opacity: 0.5
|
||||
visible:!textArea.enabled
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Scroll at end if necessary.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
Timer {
|
||||
interval: 100
|
||||
repeat: true
|
||||
running: true
|
||||
|
||||
onTriggered: chat.bindToEnd && chat.positionViewAtEnd()
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Scroll at end if necessary.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
Timer {
|
||||
interval: 100
|
||||
repeat: true
|
||||
running: true
|
||||
|
||||
onTriggered: chat.bindToEnd && chat.positionViewAtEnd()
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -414,6 +414,17 @@ ColumnLayout {
|
|||
|
||||
onClicked: Logic.updateChatFilter(button)
|
||||
}
|
||||
BusyIndicator{
|
||||
id: chatLoading
|
||||
width: 20
|
||||
height: 20
|
||||
anchors.left: filterButtons.right
|
||||
anchors.leftMargin: 50
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
//anchors.horizontalCenter: parent.horizontalCenter
|
||||
visible: chatArea.tryingToLoadMoreEntries
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Search.
|
||||
// -------------------------------------------------------------------------
|
||||
|
|
@ -422,9 +433,9 @@ ColumnLayout {
|
|||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left : filterButtons.right
|
||||
anchors.left : chatLoading.right
|
||||
anchors.rightMargin: 10
|
||||
anchors.leftMargin: 80
|
||||
anchors.leftMargin: 50
|
||||
anchors.topMargin: 10
|
||||
anchors.bottomMargin: 10
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue