Commit aeabbb7c authored by Ronan Abhamon's avatar Ronan Abhamon

unstable (chat refactoring)

parent 14aa6a9c
...@@ -267,6 +267,7 @@ ...@@ -267,6 +267,7 @@
<file>ui/modules/Linphone/Calls/CallControls.qml</file> <file>ui/modules/Linphone/Calls/CallControls.qml</file>
<file>ui/modules/Linphone/Calls/Calls.qml</file> <file>ui/modules/Linphone/Calls/Calls.qml</file>
<file>ui/modules/Linphone/CardBlock.qml</file> <file>ui/modules/Linphone/CardBlock.qml</file>
<file>ui/modules/Linphone/Chat/Chat.js</file>
<file>ui/modules/Linphone/Chat/Chat.qml</file> <file>ui/modules/Linphone/Chat/Chat.qml</file>
<file>ui/modules/Linphone/Chat/Event.qml</file> <file>ui/modules/Linphone/Chat/Event.qml</file>
<file>ui/modules/Linphone/Chat/FileMessage.qml</file> <file>ui/modules/Linphone/Chat/FileMessage.qml</file>
......
// =============================================================================
// `Chat.qml` Logic.
// =============================================================================
function initView () {
chat.tryToLoadMoreEntries = false
chat.bindToEnd = true
chat.positionViewAtEnd()
}
function loadMoreEntries () {
if (chat.atYBeginning && !chat.tryToLoadMoreEntries) {
chat.tryToLoadMoreEntries = true
chat.positionViewAtBeginning()
proxyModel.loadMoreEntries()
}
}
function getComponentFromEntry (chatEntry) {
if (chatEntry.fileName) {
return 'FileMessage.qml'
}
if (chatEntry.type === ChatModel.CallEntry) {
return 'Event.qml'
}
return chatEntry.isOutgoing ? 'OutgoingMessage.qml' : 'IncomingMessage.qml'
}
function handleCurrentItemChanged (currentItem) {
// Go to last item only!
if (!chat.bindToEnd || !currentItem || chat.currentIndex + 1 !== chat.count) {
return
}
var chatHeight = chat.height
var messageY = currentItem.mapToItem(chat.contentItem, 0, 0).y
var messageHeight = currentItem.height
console.log(chat.contentY, chatHeight, messageY)
if (chat.contentY <= messageY) {
chat.contentY = messageY
}
chat.currentIndex = -1
}
function handleFilesDropped (files) {
chat.bindToEnd = true
files.forEach(proxyModel.sendFileMessage)
}
function handleMoreEntriesLoaded (n) {
chat.positionViewAtIndex(n - 1, ListView.Beginning)
chat.tryToLoadMoreEntries = false
}
function handleMovementEnded () {
if (chat.atYEnd) {
chat.bindToEnd = true
}
}
function handleMovementStarted () {
chat.bindToEnd = false
}
function handleDataChanged (_, bottomRight) {
var n = chat.count
var index = bottomRight.row
if (chat.bindToEnd && index + 1 === n) {
chat.currentIndex = index
}
}
function sendMessage (text) {
textArea.text = ''
chat.bindToEnd = true
proxyModel.sendMessage(text)
}
...@@ -5,16 +5,14 @@ import QtQuick.Layouts 1.3 ...@@ -5,16 +5,14 @@ import QtQuick.Layouts 1.3
import Common 1.0 import Common 1.0
import Linphone 1.0 import Linphone 1.0
import Linphone.Styles 1.0 import Linphone.Styles 1.0
import Utils 1.0
import 'Chat.js' as Logic
// ============================================================================= // =============================================================================
Rectangle { Rectangle {
property alias proxyModel: chat.model property alias proxyModel: chat.model
property bool _bindToEnd: false
property var _contactObserver: SipAddressesModel.getContactObserver(proxyModel.sipAddress)
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
signal messageToSend (string text) signal messageToSend (string text)
...@@ -32,30 +30,17 @@ Rectangle { ...@@ -32,30 +30,17 @@ Rectangle {
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
property bool _tryToLoadMoreEntries: true property bool bindToEnd: false
property bool tryToLoadMoreEntries: true
// ----------------------------------------------------------------------- property var contactObserver: SipAddressesModel.getContactObserver(proxyModel.sipAddress)
function _loadMoreEntries () {
if (atYBeginning && !_tryToLoadMoreEntries) {
_tryToLoadMoreEntries = true
positionViewAtBeginning()
proxyModel.loadMoreEntries()
}
}
function _initView () {
_tryToLoadMoreEntries = false
_bindToEnd = true
positionViewAtEnd()
}
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
Layout.fillHeight: true Layout.fillHeight: true
Layout.fillWidth: true Layout.fillWidth: true
highlightFollowsCurrentItem: false
section { section {
criteria: ViewSection.FullString criteria: ViewSection.FullString
delegate: sectionHeading delegate: sectionHeading
...@@ -64,32 +49,12 @@ Rectangle { ...@@ -64,32 +49,12 @@ Rectangle {
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
Component.onCompleted: { Component.onCompleted: Logic.initView()
function goToEnd () {
return Utils.setTimeout(chat, 100, function () {
if (_bindToEnd) {
positionViewAtEnd()
}
return goToEnd() onContentYChanged: Logic.loadMoreEntries()
}) onCurrentItemChanged: Logic.handleCurrentItemChanged(currentItem)
} onMovementEnded: Logic.handleMovementEnded()
goToEnd() onMovementStarted: Logic.handleMovementStarted()
// First render.
_initView()
}
// -----------------------------------------------------------------------
onMovementStarted: _bindToEnd = false
onMovementEnded: {
if (atYEnd) {
_bindToEnd = true
}
}
onContentYChanged: _loadMoreEntries()
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
...@@ -99,12 +64,9 @@ Rectangle { ...@@ -99,12 +64,9 @@ Rectangle {
// When the view is changed (for example `Calls` -> `Messages`), // When the view is changed (for example `Calls` -> `Messages`),
// the position is set at end and it can be possible to load // the position is set at end and it can be possible to load
// more entries. // more entries.
onEntryTypeFilterChanged: chat._initView() onEntryTypeFilterChanged: Logic.initView()
onMoreEntriesLoaded: Logic.handleMoreEntriesLoaded(n)
onMoreEntriesLoaded: { onDataChanged: Logic.handleDataChanged(topLeft, bottomRight)
chat.positionViewAtIndex(n - 1, ListView.Beginning)
chat._tryToLoadMoreEntries = false
}
} }
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
...@@ -171,45 +133,18 @@ Rectangle { ...@@ -171,45 +133,18 @@ Rectangle {
leftMargin: ChatStyle.entry.leftMargin leftMargin: ChatStyle.entry.leftMargin
right: parent ? parent.right : undefined right: parent ? parent.right : undefined
// Ugly. I admit it, but it exists a problem, without these
// lines the extra content message is truncated.
// I have no other solution at this moment with `anchors`
// properties... The messages use the `implicitWidth/Height`
// and `width/Height` attrs and is not easy to found a fix.
rightMargin: ChatStyle.entry.deleteIconSize + rightMargin: ChatStyle.entry.deleteIconSize +
ChatStyle.entry.message.extraContent.spacing + ChatStyle.entry.message.extraContent.spacing +
ChatStyle.entry.message.extraContent.rightMargin + ChatStyle.entry.message.extraContent.rightMargin +
ChatStyle.entry.message.extraContent.leftMargin + ChatStyle.entry.message.extraContent.leftMargin +
ChatStyle.entry.message.outgoing.sendIconSize ChatStyle.entry.message.outgoing.sendIconSize
} }
color: ChatStyle.color color: ChatStyle.color
implicitHeight: layout.height + ChatStyle.entry.bottomMargin implicitHeight: layout.height + ChatStyle.entry.bottomMargin
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
// Avoid the use of explicit qrc paths.
Component {
id: event
Event {}
}
Component {
id: incomingMessage
IncomingMessage {}
}
Component {
id: outgoingMessage
OutgoingMessage {}
}
Component {
id: fileMessage
FileMessage {}
}
// ---------------------------------------------------------------------
MouseArea { MouseArea {
id: mouseArea id: mouseArea
...@@ -228,29 +163,22 @@ Rectangle { ...@@ -228,29 +163,22 @@ Rectangle {
Layout.alignment: Qt.AlignTop Layout.alignment: Qt.AlignTop
Layout.preferredHeight: ChatStyle.entry.lineHeight Layout.preferredHeight: ChatStyle.entry.lineHeight
Layout.preferredWidth: ChatStyle.entry.time.width Layout.preferredWidth: ChatStyle.entry.time.width
color: ChatStyle.entry.time.color color: ChatStyle.entry.time.color
font.pointSize: ChatStyle.entry.time.fontSize font.pointSize: ChatStyle.entry.time.fontSize
text: $chatEntry.timestamp.toLocaleString( text: $chatEntry.timestamp.toLocaleString(
Qt.locale(App.locale), Qt.locale(App.locale),
'hh:mm' 'hh:mm'
) )
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
} }
// Display content. // Display content.
Loader { Loader {
Layout.fillWidth: true Layout.fillWidth: true
sourceComponent: { source: Logic.getComponentFromEntry($chatEntry)
if ($chatEntry.fileName) {
return fileMessage
}
if ($chatEntry.type === ChatModel.CallEntry) {
return event
}
return $chatEntry.isOutgoing ? outgoingMessage : incomingMessage
}
} }
} }
} }
...@@ -263,27 +191,22 @@ Rectangle { ...@@ -263,27 +191,22 @@ Rectangle {
Borders { Borders {
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: ChatStyle.sendArea.height + Layout.preferredHeight: ChatStyle.sendArea.height + ChatStyle.sendArea.border.width
ChatStyle.sendArea.border.width
borderColor: ChatStyle.sendArea.border.color borderColor: ChatStyle.sendArea.border.color
topWidth: ChatStyle.sendArea.border.width topWidth: ChatStyle.sendArea.border.width
DroppableTextArea { DroppableTextArea {
id: textArea
anchors.fill: parent anchors.fill: parent
dropEnabled: SettingsModel.fileTransferUrl.length > 0 dropEnabled: SettingsModel.fileTransferUrl.length > 0
dropDisabledReason: qsTr('noFileTransferUrl') dropDisabledReason: qsTr('noFileTransferUrl')
placeholderText: qsTr('newMessagePlaceholder') placeholderText: qsTr('newMessagePlaceholder')
onDropped: { onDropped: Logic.handleFilesDropped(files)
_bindToEnd = true onValidText: Logic.sendMessage(text)
files.forEach(proxyModel.sendFileMessage)
}
onValidText: {
this.text = ''
_bindToEnd = true
proxyModel.sendMessage(text)
}
} }
} }
} }
......
...@@ -27,8 +27,8 @@ Row { ...@@ -27,8 +27,8 @@ Row {
height: ChatStyle.entry.message.incoming.avatarSize height: ChatStyle.entry.message.incoming.avatarSize
width: ChatStyle.entry.message.incoming.avatarSize width: ChatStyle.entry.message.incoming.avatarSize
image: _contactObserver.contact ? _contactObserver.contact.avatar : '' image: chat.contactObserver.contact ? chat.contactObserver.contact.avatar : ''
username: LinphoneUtils.getContactUsername(_contactObserver.contact || proxyModel.sipAddress) username: LinphoneUtils.getContactUsername(chat.contactObserver.contact || proxyModel.sipAddress)
} }
} }
......
...@@ -20,8 +20,8 @@ RowLayout { ...@@ -20,8 +20,8 @@ RowLayout {
Avatar { Avatar {
anchors.centerIn: parent anchors.centerIn: parent
height: ChatStyle.entry.message.incoming.avatarSize height: ChatStyle.entry.message.incoming.avatarSize
image: _contactObserver.contact ? _contactObserver.contact.avatar : '' image: chat.contactObserver.contact ? chat.contactObserver.contact.avatar : ''
username: LinphoneUtils.getContactUsername(_contactObserver.contact || proxyModel.sipAddress) username: LinphoneUtils.getContactUsername(chat.contactObserver.contact || proxyModel.sipAddress)
width: ChatStyle.entry.message.incoming.avatarSize width: ChatStyle.entry.message.incoming.avatarSize
// The avatar is only visible for the first message of a incoming messages sequence. // The avatar is only visible for the first message of a incoming messages sequence.
......
// =============================================================================
// `Message.qml` Logic.
// =============================================================================
// See: `ensureVisible` on http://doc.qt.io/qt-5/qml-qtquick-textedit.html // See: `ensureVisible` on http://doc.qt.io/qt-5/qml-qtquick-textedit.html
function ensureVisible (cursor) { function ensureVisible (cursor) {
// Case 1: No focused. // Case 1: No focused.
if (!message.activeFocus) { if (!message.activeFocus) {
return return
} }
// Case 2: Scroll up. // Case 2: Scroll up.
var contentItem = chat.contentItem var contentItem = chat.contentItem
var contentY = chat.contentY var contentY = chat.contentY
var messageY = message.mapToItem(contentItem, 0, 0).y + cursor.y var messageY = message.mapToItem(contentItem, 0, 0).y + cursor.y
if (contentY >= messageY) { if (contentY >= messageY) {
chat.contentY = messageY chat.contentY = messageY
return return
} }
// Case 3: Scroll down. // Case 3: Scroll down.
var chatHeight = chat.height var chatHeight = chat.height
var cursorHeight = cursor.height var cursorHeight = cursor.height
if (contentY + chatHeight <= messageY + cursorHeight) { if (contentY + chatHeight <= messageY + cursorHeight) {
chat.contentY = messageY + cursorHeight - chatHeight chat.contentY = messageY + cursorHeight - chatHeight
} }
} }
...@@ -59,7 +59,7 @@ Item { ...@@ -59,7 +59,7 @@ Item {
// See http://doc.qt.io/qt-5/qml-qtquick-text.html#textFormat-prop // See http://doc.qt.io/qt-5/qml-qtquick-text.html#textFormat-prop
// and http://doc.qt.io/qt-5/richtext-html-subset.html // and http://doc.qt.io/qt-5/richtext-html-subset.html
textFormat: Text.RichText // To supports links and imgs. textFormat: Text.RichText // To supports links and imgs.
wrapMode: TextEdit.WordWrap wrapMode: TextEdit.Wrap
onCursorRectangleChanged: Logic.ensureVisible(cursorRectangle) onCursorRectangleChanged: Logic.ensureVisible(cursorRectangle)
onLinkActivated: Qt.openUrlExternally(link) onLinkActivated: Qt.openUrlExternally(link)
......
...@@ -9,7 +9,7 @@ import App.Styles 1.0 ...@@ -9,7 +9,7 @@ import App.Styles 1.0
// ============================================================================= // =============================================================================
Item { Item {
id: assistant id: assistant
readonly property string viewsPath: 'qrc:/ui/views/App/Main/Assistant/' readonly property string viewsPath: 'qrc:/ui/views/App/Main/Assistant/'
...@@ -54,8 +54,8 @@ Item { ...@@ -54,8 +54,8 @@ Item {
YAnimator { YAnimator {
duration: AssistantStyle.stackAnimation.duration duration: AssistantStyle.stackAnimation.duration
easing.type: Easing.OutBack easing.type: Easing.OutBack
from: stack.height + AssistantStyle.bottomMargin from: stack.height + AssistantStyle.bottomMargin
to: 0 to: 0
} }
} }
...@@ -66,7 +66,7 @@ Item { ...@@ -66,7 +66,7 @@ Item {
from: 0 from: 0
to: stack.width + AssistantStyle.rightMargin to: stack.width + AssistantStyle.rightMargin
} }
} }
pushEnter: Transition { pushEnter: Transition {
XAnimator { XAnimator {
...@@ -81,9 +81,9 @@ Item { ...@@ -81,9 +81,9 @@ Item {
YAnimator { YAnimator {
duration: AssistantStyle.stackAnimation.duration duration: AssistantStyle.stackAnimation.duration
easing.type: Easing.OutBack easing.type: Easing.OutBack
from: 0 from: 0
to: stack.height + AssistantStyle.bottomMargin to: stack.height + AssistantStyle.bottomMargin
} }
} }
} }
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment