diff --git a/src/jamichatview/jamichatview.qrc b/src/jamichatview/jamichatview.qrc
index f2262078..fcaadf87 100644
--- a/src/jamichatview/jamichatview.qrc
+++ b/src/jamichatview/jamichatview.qrc
@@ -1,16 +1,17 @@
qml/chatbox.qml
qml/chatview.qml
qml/textbubble.qml
qml/categoryheader.qml
qml/textmessagegroup.qml
qml/callgroup.qml
qml/groupheader.qml
qml/groupfooter.qml
qml/chatpage.qml
+ qml/navigation.qml
qml/snapshots.qml
qml/slideshow.qml
qml/thumbnail.qml
diff --git a/src/jamichatview/plugin.cpp b/src/jamichatview/plugin.cpp
index 58419306..6fbd3100 100644
--- a/src/jamichatview/plugin.cpp
+++ b/src/jamichatview/plugin.cpp
@@ -1,54 +1,55 @@
/************************************************************************************
* Copyright (C) 2018 by BlueSystems GmbH *
* Author : Emmanuel Lepage Vallee *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
***********************************************************************************/
#include "plugin.h"
// Qt
#include
#include
// QRC
#include
// ChatView
#include "bubble.h"
void JamiChatView::registerTypes(const char *uri)
{
Q_ASSERT(uri == QByteArray("org.kde.ringkde.jamichatview"));
qmlRegisterType(uri, 1, 0, "Bubble");
qmlRegisterType(QStringLiteral("qrc:/jamichatview/qml/chatbox.qml") , uri, 1, 0, "ChatBox");
qmlRegisterType(QStringLiteral("qrc:/jamichatview/qml/chatview.qml") , uri, 1, 0, "ChatView");
qmlRegisterType(QStringLiteral("qrc:/jamichatview/qml/textbubble.qml") , uri, 1, 0, "TextBubble");
qmlRegisterType(QStringLiteral("qrc:/jamichatview/qml/categoryheader.qml") , uri, 1, 0, "CategoryHeader");
qmlRegisterType(QStringLiteral("qrc:/jamichatview/qml/textmessagegroup.qml"), uri, 1, 0, "TextMessageGroup");
qmlRegisterType(QStringLiteral("qrc:/jamichatview/qml/callgroup.qml") , uri, 1, 0, "CallGroup");
qmlRegisterType(QStringLiteral("qrc:/jamichatview/qml/groupheader.qml") , uri, 1, 0, "GroupHeader");
qmlRegisterType(QStringLiteral("qrc:/jamichatview/qml/groupfooter.qml") , uri, 1, 0, "GroupFooter");
qmlRegisterType(QStringLiteral("qrc:/jamichatview/qml/snapshots.qml") , uri, 1, 0, "Snapshots");
qmlRegisterType(QStringLiteral("qrc:/jamichatview/qml/slideshow.qml") , uri, 1, 0, "Slideshow");
qmlRegisterType(QStringLiteral("qrc:/jamichatview/qml/thumbnail.qml") , uri, 1, 0, "Thumbnail");
- qmlRegisterType(QStringLiteral("qrc:/jamichatview/qml/chatpage.qml") , uri, 1, 0, "ChatPage");
+ qmlRegisterType(QStringLiteral("qrc:/jamichatview/qml/chatpage.qml") , uri, 1, 0, "ChatPage");
+ qmlRegisterType(QStringLiteral("qrc:/jamichatview/qml/navigation.qml") , uri, 1, 0, "Navigation");
}
void JamiChatView::initializeEngine(QQmlEngine *engine, const char *uri)
{
Q_UNUSED(engine)
Q_UNUSED(uri)
}
diff --git a/src/jamichatview/qml/chatpage.qml b/src/jamichatview/qml/chatpage.qml
index df1e43e0..337ae459 100644
--- a/src/jamichatview/qml/chatpage.qml
+++ b/src/jamichatview/qml/chatpage.qml
@@ -1,239 +1,270 @@
/***************************************************************************
* Copyright (C) 2017 by Bluesystems *
* Author : Emmanuel Lepage Vallee *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see . *
**************************************************************************/
import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.0
import org.kde.kirigami 2.2 as Kirigami
import QtGraphicalEffects 1.0
import org.kde.ringkde.jamitimeline 1.0 as JamiTimeline
import org.kde.ringkde.jamitimelinebase 1.0 as JamiTimelineBase
import org.kde.ringkde.jamichatview 1.0 as JamiChatView
import org.kde.ringkde.jamicontactview 1.0 as JamiContactView
import net.lvindustries.ringqtquick 1.0 as RingQtQuick
+import org.kde.playground.kquickitemviews 1.0 as KQuickItemViews
Rectangle {
id: timelinePage
signal disableContactRequests()
property bool showScrollbar: true
property bool _sendRequestOverride: true
+ property var currentContactMethod: null
+ property var currentIndividual: null
+ property var timelineModel: null
+
+ property bool canSendTexts: currentIndividual ? currentIndividual.canSendTexts : false
+
property bool sendRequest: _sendRequestOverride && (
sendRequestLoader.active && sendRequestLoader.item && sendRequestLoader.item.sendRequests
)
onDisableContactRequests: {
if (timelinePage.setContactMethod())
currentContactMethod.confirmationEnabled = false
timelinePage._sendRequestOverride = send
}
Kirigami.Theme.colorSet: Kirigami.Theme.View
function focusEdit() {
chatBox.focusEdit()
}
function showNewContent() {
chatView.moveTo(Qt.BottomEdge)
}
function setContactMethod() {
if (currentIndividual && !currentContactMethod) {
currentContactMethod = currentIndividual.preferredContactMethod(
RingQtQuick.Media.TEXT
)
if (!currentContactMethod)
console.log("Cannot find a valid ContactMethod for", currentIndividual)
}
return currentContactMethod
}
onCurrentIndividualChanged: {
currentContactMethod = null
setContactMethod()
}
color: Kirigami.Theme.backgroundColor
- property var currentContactMethod: null
- property var currentIndividual: null
- property var timelineModel: null
+ // Scroll to the search, unread messages, bookmark, etc
+ RingQtQuick.TimelineIterator {
+ id: iterator
+ currentIndividual: timelinePage.currentIndividual
+ firstVisibleIndex: chatView.topLeft
+ lastVisibleIndex: chatView.bottomLeft
+ onContentAdded: {
+ lastVisibleIndex = chatView.indexAt(Qt.BottomEdge)
+ timelinePage.showNewContent()
+ }
- property bool canSendTexts: currentIndividual ? currentIndividual.canSendTexts : false
+ onProposeIndex: {
+ if (poposedIndex == newestIndex)
+ timelinePage.showNewContent()
+ else
+ chatView.contentY = chatView.itemRect(newestIndex).y
+ }
+ }
onTimelineModelChanged: {
if (!fixmeTimer.running)
chatView.model = timelineModel
}
// Add a blurry background
ShaderEffectSource {
id: effectSource
visible: chatView.displayExtraTime
sourceItem: chatView
anchors.right: timelinePage.right
anchors.top: timelinePage.top
width: scrollbar.fullWidth + 15
height: chatView.height
sourceRect: Qt.rect(
blurryOverlay.x,
blurryOverlay.y,
blurryOverlay.width,
blurryOverlay.height
)
}
ColumnLayout {
anchors.fill: parent
clip: true
spacing: 0
Loader {
id: sendRequestLoader
height: active && item ? item.implicitHeight : 0
Layout.fillWidth: true
active: chatBox.requireContactRequest
Layout.minimumHeight: active && item ? item.implicitHeight : 0
Layout.maximumHeight: active && item ? item.implicitHeight : 0
sourceComponent: JamiContactView.SendRequest {
width: sendRequestLoader.width
}
}
RowLayout {
id: chatScrollView
Layout.fillHeight: true
Layout.fillWidth: true
Layout.bottomMargin: 0
property bool lock: false
Item {
Layout.fillHeight: true
Layout.fillWidth: true
+ // Buttons to navigate to relevant content
+ JamiChatView.Navigation {
+ timelineIterator: iterator
+ anchors.rightMargin: blurryOverlay.width
+ anchors.right: parent.right
+ anchors.bottom: parent.bottom
+ Behavior on anchors.rightMargin {
+ NumberAnimation {duration: 100; easing.type: Easing.InQuad}
+ }
+ }
+
JamiChatView.ChatView {
id: chatView
width: Math.min(600, timelinePage.width - 50)
height: parent.height
anchors.horizontalCenter: parent.horizontalCenter
model: null//FIXME timelinePage.timelineModel
forceTime: scrollbar.overlayVisible
// Due to a race condition, wait a bit, it should be fixed elsewhere,
//FIXME but it would take much longer.
Timer {
id: fixmeTimer
repeat: false
running: true
interval: 33
onTriggered: {
chatView.model = timelinePage.timelineModel
}
}
}
// It needs to be here due to z-index conflicts between
// chatScrollView and timelinePage
Item {
id: blurryOverlay
z: 2
opacity: chatView.displayExtraTime && scrollbar.hasContent ? 1 : 0
anchors.right: parent.right
anchors.top: parent.top
anchors.rightMargin: - 15
height: chatScrollView.height
clip: true
width: chatView.displayExtraTime ?
scrollbar.fullWidth + 15 : 0
visible: opacity > 0
Behavior on opacity {
NumberAnimation {duration: 300; easing.type: Easing.InQuad}
}
Repeater {
anchors.fill: parent
model: 5
FastBlur {
anchors.fill: parent
source: effectSource
radius: 30
}
}
Rectangle {
anchors.fill: parent
color: Kirigami.Theme.backgroundColor
opacity: 0.75
}
}
}
JamiTimelineBase.Scrollbar {
id: scrollbar
z: 1000
bottomUp: true
Layout.fillHeight: true
Layout.preferredWidth: 10
display: chatView.moving || timelinePage.showScrollbar
model: timelinePage.timelineModel
view: chatView
forceOverlay: chatView.displayExtraTime
}
}
Kirigami.Separator {
Layout.fillWidth: true
}
JamiChatView.ChatBox {
id: chatBox
Layout.fillWidth: true
height: 90
visible: canSendTexts
RingQtQuick.MessageBuilder {id: builder}
requireContactRequest: currentContactMethod &&
currentContactMethod.confirmationStatus == RingQtQuick.ContactMethod.UNCONFIRMED &&
currentContactMethod.confirmationStatus != RingQtQuick.ContactMethod.DISABLED
textColor: Kirigami.Theme.textColor
backgroundColor: Kirigami.Theme.backgroundColor
emojiColor: Kirigami.Theme.highlightColor
}
}
Connections {
target: chatBox
onSendMessage: {
timelinePage.setContactMethod()
if (currentContactMethod) {
if (currentContactMethod.account && currentContactMethod.confirmationStatus == RingQtQuick.ContactMethod.UNCONFIRMED)
currentContactMethod.sendContactRequest()
builder.addPayload("text/plain", message)
builder.sendWidth(currentContactMethod)
}
}
}
}
diff --git a/src/jamichatview/qml/navigation.qml b/src/jamichatview/qml/navigation.qml
new file mode 100644
index 00000000..8a6bf8d6
--- /dev/null
+++ b/src/jamichatview/qml/navigation.qml
@@ -0,0 +1,60 @@
+/***************************************************************************
+ * Copyright (C) 2019 by Bluesystems *
+ * Author : Emmanuel Lepage Vallee *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 3 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program. If not, see . *
+ **************************************************************************/
+import QtQuick 2.9
+import org.kde.kirigami 2.2 as Kirigami
+
+Column {
+ property QtObject timelineIterator: null
+ property int buttonCount: 1
+ spacing: Kirigami.Units.largeSpacing
+ property real buttonSize: Kirigami.Units.iconSizes.large
+ width: buttonCount > 0 ? buttonSize : 0
+ height: buttonCount * buttonSize + buttonCount*spacing
+ visible: opacity > 0
+ opacity: buttonCount > 0 ? 1 : 0
+ z: 200
+
+ Behavior on opacity {
+ NumberAnimation {duration: 200; easing.type: Easing.InQuad}
+ }
+
+ Rectangle {
+ color: Kirigami.Theme.highlightColor
+ radius: 99
+ height: buttonSize
+ width: buttonSize
+ opacity: chatView.contentHeight - (chatView.contentY + chatView.height) < 10 ? 0 : 1
+ visible: opacity > 0
+ border.width: 2
+ border.color: Kirigami.Theme.highlightedTextColor
+ Kirigami.Icon {
+ source: "go-down"
+ color: Kirigami.Theme.highlightedTextColor
+ width: Kirigami.Units.iconSizes.smallMedium
+ height: Kirigami.Units.iconSizes.smallMedium
+ anchors.centerIn: parent
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ onClicked: {
+ timelineIterator.proposeNewest()
+ }
+ }
+ }
+}