copy message text to clipboard + improve chat message and sending area ui
This commit is contained in:
parent
ecd9373df9
commit
73b83771be
9 changed files with 197 additions and 113 deletions
|
|
@ -97,10 +97,12 @@ void ChatList::setSelf(QSharedPointer<ChatList> me) {
|
||||||
std::find_if(list.begin(), list.end(), [chatRoom](const QSharedPointer<ChatCore> &item) {
|
std::find_if(list.begin(), list.end(), [chatRoom](const QSharedPointer<ChatCore> &item) {
|
||||||
return (item && item->getModel()->getMonitor() == chatRoom);
|
return (item && item->getModel()->getMonitor() == chatRoom);
|
||||||
});
|
});
|
||||||
if (found != list.end()) {
|
if (found == list.end()) {
|
||||||
qDebug() << "chat room created, add it to the list";
|
|
||||||
auto model = createChatCore(chatRoom);
|
auto model = createChatCore(chatRoom);
|
||||||
mModelConnection->invokeToCore([this, model]() { add(model); });
|
mModelConnection->invokeToCore([this, model]() {
|
||||||
|
add(model);
|
||||||
|
emit chatAdded();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,7 @@ signals:
|
||||||
void lUpdate();
|
void lUpdate();
|
||||||
void filterChanged(QString filter);
|
void filterChanged(QString filter);
|
||||||
void chatRemoved(ChatGui *chat);
|
void chatRemoved(ChatGui *chat);
|
||||||
|
void chatAdded();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString mFilter;
|
QString mFilter;
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ DEFINE_ABSTRACT_OBJECT(ChatProxy)
|
||||||
ChatProxy::ChatProxy(QObject *parent) : LimitProxy(parent) {
|
ChatProxy::ChatProxy(QObject *parent) : LimitProxy(parent) {
|
||||||
mList = ChatList::create();
|
mList = ChatList::create();
|
||||||
setSourceModel(mList.get());
|
setSourceModel(mList.get());
|
||||||
|
setDynamicSortFilter(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
ChatProxy::~ChatProxy() {
|
ChatProxy::~ChatProxy() {
|
||||||
|
|
@ -43,8 +44,10 @@ void ChatProxy::setSourceModel(QAbstractItemModel *model) {
|
||||||
connect(this, &ChatProxy::filterTextChanged, newChatList,
|
connect(this, &ChatProxy::filterTextChanged, newChatList,
|
||||||
[this, newChatList] { emit newChatList->filterChanged(getFilterText()); });
|
[this, newChatList] { emit newChatList->filterChanged(getFilterText()); });
|
||||||
connect(newChatList, &ChatList::chatRemoved, this, &ChatProxy::chatRemoved);
|
connect(newChatList, &ChatList::chatRemoved, this, &ChatProxy::chatRemoved);
|
||||||
|
connect(newChatList, &ChatList::chatAdded, this, [this] { invalidate(); });
|
||||||
}
|
}
|
||||||
setSourceModels(new SortFilterList(model));
|
auto firstList = new SortFilterList(model, Qt::AscendingOrder);
|
||||||
|
setSourceModels(firstList);
|
||||||
sort(0);
|
sort(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,9 +13,11 @@ Button {
|
||||||
radius: Math.round(5 * DefaultStyle.dp)
|
radius: Math.round(5 * DefaultStyle.dp)
|
||||||
shadowEnabled: mainItem.activeFocus || hovered
|
shadowEnabled: mainItem.activeFocus || hovered
|
||||||
style: ButtonStyle.hoveredBackground
|
style: ButtonStyle.hoveredBackground
|
||||||
|
property bool inverseLayout: false
|
||||||
|
|
||||||
contentItem: RowLayout {
|
contentItem: RowLayout {
|
||||||
spacing: Math.round(5 * DefaultStyle.dp)
|
spacing: Math.round(5 * DefaultStyle.dp)
|
||||||
|
layoutDirection: mainItem.inverseLayout ? Qt.RightToLeft: Qt.LeftToRight
|
||||||
EffectImage {
|
EffectImage {
|
||||||
imageSource: mainItem.icon.source
|
imageSource: mainItem.icon.source
|
||||||
imageWidth: mainItem.icon.width
|
imageWidth: mainItem.icon.width
|
||||||
|
|
@ -33,6 +35,7 @@ Button {
|
||||||
horizontalAlignment: Text.AlignLeft
|
horizontalAlignment: Text.AlignLeft
|
||||||
verticalAlignment: Text.AlignVCenter
|
verticalAlignment: Text.AlignVCenter
|
||||||
Layout.preferredWidth: textMetrics.advanceWidth
|
Layout.preferredWidth: textMetrics.advanceWidth
|
||||||
|
Layout.fillWidth: true
|
||||||
wrapMode: Text.WrapAnywhere
|
wrapMode: Text.WrapAnywhere
|
||||||
text: mainItem.text
|
text: mainItem.text
|
||||||
maximumLineCount: 1
|
maximumLineCount: 1
|
||||||
|
|
|
||||||
|
|
@ -8,22 +8,43 @@ import SettingsCpp
|
||||||
import "qrc:/qt/qml/Linphone/view/Style/buttonStyle.js" as ButtonStyle
|
import "qrc:/qt/qml/Linphone/view/Style/buttonStyle.js" as ButtonStyle
|
||||||
import "qrc:/qt/qml/Linphone/view/Control/Tool/Helper/utils.js" as Utils
|
import "qrc:/qt/qml/Linphone/view/Control/Tool/Helper/utils.js" as Utils
|
||||||
|
|
||||||
|
Control.Control {
|
||||||
RowLayout {
|
|
||||||
id: mainItem
|
id: mainItem
|
||||||
property color backgroundColor
|
property color backgroundColor
|
||||||
property bool isFirstMessage
|
property bool isFirstMessage
|
||||||
|
|
||||||
property string imgUrl
|
property string imgUrl
|
||||||
spacing: 0
|
|
||||||
|
|
||||||
property ChatMessageGui chatMessage
|
property ChatMessageGui chatMessage
|
||||||
property string fromAddress: chatMessage? chatMessage.core.fromAddress : ""
|
property string fromAddress: chatMessage? chatMessage.core.fromAddress : ""
|
||||||
property bool isRemoteMessage: chatMessage? chatMessage.core.isRemoteMessage : false
|
property bool isRemoteMessage: chatMessage? chatMessage.core.isRemoteMessage : false
|
||||||
property bool isFromChatGroup: chatMessage? chatMessage.core.isFromChatGroup : false
|
property bool isFromChatGroup: chatMessage? chatMessage.core.isFromChatGroup : false
|
||||||
|
hoverEnabled: true
|
||||||
|
|
||||||
signal messageDeletionRequested()
|
signal messageDeletionRequested()
|
||||||
|
|
||||||
|
background: Item {
|
||||||
|
anchors.fill: parent
|
||||||
|
Text {
|
||||||
|
id: fromNameText
|
||||||
|
visible: mainItem.isFromChatGroup && mainItem.isRemoteMessage && mainItem.isFirstMessage
|
||||||
|
anchors.top: parent.top
|
||||||
|
maximumLineCount: 1
|
||||||
|
width: implicitWidth
|
||||||
|
x: chatBubble.x
|
||||||
|
text: mainItem.chatMessage.core.fromName
|
||||||
|
color: DefaultStyle.main2_500main
|
||||||
|
font {
|
||||||
|
pixelSize: Typography.p4.pixelSize
|
||||||
|
weight: Typography.p4.weight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contentItem: RowLayout {
|
||||||
|
spacing: 0
|
||||||
|
layoutDirection: mainItem.isRemoteMessage ? Qt.LeftToRight : Qt.RightToLeft
|
||||||
|
|
||||||
Avatar {
|
Avatar {
|
||||||
id: avatar
|
id: avatar
|
||||||
visible: mainItem.isFromChatGroup
|
visible: mainItem.isFromChatGroup
|
||||||
|
|
@ -35,10 +56,11 @@ RowLayout {
|
||||||
_address: chatMessage ? chatMessage.core.fromAddress : ""
|
_address: chatMessage ? chatMessage.core.fromAddress : ""
|
||||||
}
|
}
|
||||||
Control.Control {
|
Control.Control {
|
||||||
|
id: chatBubble
|
||||||
Layout.topMargin: isFirstMessage ? 16 * DefaultStyle.dp : 0
|
Layout.topMargin: isFirstMessage ? 16 * DefaultStyle.dp : 0
|
||||||
Layout.leftMargin: mainItem.isFromChatGroup ? Math.round(9 * DefaultStyle.dp) : 0
|
Layout.leftMargin: mainItem.isFromChatGroup ? Math.round(9 * DefaultStyle.dp) : 0
|
||||||
Layout.preferredWidth: Math.min(implicitWidth, mainItem.maxWidth - avatar.implicitWidth)
|
Layout.preferredWidth: Math.min(implicitWidth, mainItem.maxWidth - avatar.implicitWidth)
|
||||||
// Layout.topMargin: name.visible ? Math.round(7 * DefaultStyle.dp) : 0
|
spacing: Math.round(2 * DefaultStyle.dp)
|
||||||
topPadding: Math.round(12 * DefaultStyle.dp)
|
topPadding: Math.round(12 * DefaultStyle.dp)
|
||||||
bottomPadding: Math.round(12 * DefaultStyle.dp)
|
bottomPadding: Math.round(12 * DefaultStyle.dp)
|
||||||
leftPadding: Math.round(18 * DefaultStyle.dp)
|
leftPadding: Math.round(18 * DefaultStyle.dp)
|
||||||
|
|
@ -48,47 +70,11 @@ RowLayout {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
acceptedButtons: Qt.RightButton
|
acceptedButtons: Qt.RightButton
|
||||||
onClicked: (mouse) => {
|
onClicked: (mouse) => {
|
||||||
console.log("message clicked")
|
|
||||||
if (mouse.button === Qt.RightButton) {
|
if (mouse.button === Qt.RightButton) {
|
||||||
optionsMenu.x = mouse.x
|
|
||||||
optionsMenu.open()
|
optionsMenu.open()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Popup {
|
|
||||||
id: optionsMenu
|
|
||||||
background: Item {
|
|
||||||
anchors.fill: parent
|
|
||||||
Rectangle {
|
|
||||||
id: popupBackground
|
|
||||||
anchors.fill: parent
|
|
||||||
color: DefaultStyle.grey_0
|
|
||||||
radius: Math.round(16 * DefaultStyle.dp)
|
|
||||||
}
|
|
||||||
MultiEffect {
|
|
||||||
source: popupBackground
|
|
||||||
anchors.fill: popupBackground
|
|
||||||
shadowEnabled: true
|
|
||||||
shadowBlur: 0.1
|
|
||||||
shadowColor: DefaultStyle.grey_1000
|
|
||||||
shadowOpacity: 0.4
|
|
||||||
}
|
|
||||||
}
|
|
||||||
contentItem: ColumnLayout {
|
|
||||||
IconLabelButton {
|
|
||||||
//: "Supprimer"
|
|
||||||
text: qsTr("chat_message_delete")
|
|
||||||
icon.source: AppIcons.trashCan
|
|
||||||
spacing: Math.round(10 * DefaultStyle.dp)
|
|
||||||
Layout.fillWidth: true
|
|
||||||
onClicked: {
|
|
||||||
mainItem.messageDeletionRequested()
|
|
||||||
optionsMenu.close()
|
|
||||||
}
|
|
||||||
style: ButtonStyle.noBackgroundRed
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
background: Item {
|
background: Item {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
@ -141,4 +127,58 @@ RowLayout {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
RowLayout {
|
||||||
|
id: actionsLayout
|
||||||
|
visible: mainItem.hovered || optionsMenu.hovered || optionsMenu.popup.opened || emojiButton.hovered
|
||||||
|
Layout.leftMargin: Math.round(8 * DefaultStyle.dp)
|
||||||
|
Layout.rightMargin: Math.round(8 * DefaultStyle.dp)
|
||||||
|
Layout.alignment: Qt.AlignVCenter
|
||||||
|
// Layout.fillWidth: true
|
||||||
|
spacing: Math.round(7 * DefaultStyle.dp)
|
||||||
|
layoutDirection: mainItem.isRemoteMessage ? Qt.LeftToRight : Qt.RightToLeft
|
||||||
|
PopupButton {
|
||||||
|
id: optionsMenu
|
||||||
|
popup.padding: 0
|
||||||
|
popup.contentItem: ColumnLayout {
|
||||||
|
spacing: 0
|
||||||
|
IconLabelButton {
|
||||||
|
inverseLayout: true
|
||||||
|
//: "Copy"
|
||||||
|
text: qsTr("chat_message_copy")
|
||||||
|
icon.source: AppIcons.copy
|
||||||
|
// spacing: Math.round(10 * DefaultStyle.dp)
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: 45 * DefaultStyle.dp
|
||||||
|
onClicked: {
|
||||||
|
var success = UtilsCpp.copyToClipboard(modelData.core.text)
|
||||||
|
//: Copied
|
||||||
|
if (success) UtilsCpp.showInformationPopup(qsTr("chat_message_copied_to_clipboard_title"),
|
||||||
|
//: "in clipboard"
|
||||||
|
qsTr("chat_message_copied_to_clipboard_toast"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IconLabelButton {
|
||||||
|
inverseLayout: true
|
||||||
|
//: "Delete"
|
||||||
|
text: qsTr("chat_message_delete")
|
||||||
|
icon.source: AppIcons.trashCan
|
||||||
|
// spacing: Math.round(10 * DefaultStyle.dp)
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: 45 * DefaultStyle.dp
|
||||||
|
onClicked: {
|
||||||
|
mainItem.messageDeletionRequested()
|
||||||
|
optionsMenu.close()
|
||||||
|
}
|
||||||
|
style: ButtonStyle.hoveredBackgroundRed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BigButton {
|
||||||
|
id: emojiButton
|
||||||
|
style: ButtonStyle.noBackground
|
||||||
|
icon.source: AppIcons.smiley
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Item{Layout.fillWidth: true}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,13 +14,41 @@ ListView {
|
||||||
property color backgroundColor
|
property color backgroundColor
|
||||||
spacing: Math.round(4 * DefaultStyle.dp)
|
spacing: Math.round(4 * DefaultStyle.dp)
|
||||||
|
|
||||||
Component.onCompleted: positionViewAtEnd()
|
// Component.onCompleted: positionViewAtIndex(chatMessageProxy.findFirstUnreadIndex(), ListView.Visible)
|
||||||
|
|
||||||
onCountChanged: positionViewAtEnd()
|
onAtYEndChanged: if (atYEnd) chat.core.lMarkAsRead();
|
||||||
|
|
||||||
|
onChatChanged: if (visible) {
|
||||||
|
var index = chatMessageProxy.findFirstUnreadIndex()
|
||||||
|
console.log("visible, first unread at index", index)
|
||||||
|
mainItem.positionViewAtIndex(index, ListView.Visible)
|
||||||
|
}
|
||||||
|
|
||||||
|
RoundButton {
|
||||||
|
icon.source: AppIcons.downArrow
|
||||||
|
// Layout.preferredWidth: 40 * DefaultStyle.dp
|
||||||
|
// Layout.preferredHeight: 40 * DefaultStyle.dp
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.bottomMargin: Math.round(18 * DefaultStyle.dp)
|
||||||
|
anchors.rightMargin: Math.round(18 * DefaultStyle.dp)
|
||||||
|
onClicked: {
|
||||||
|
var index = chatMessageProxy.findFirstUnreadIndex()
|
||||||
|
console.log("clicked, first unread at index", index)
|
||||||
|
mainItem.positionViewAtIndex(index, ListView.Visible)
|
||||||
|
// var chatMessage = chatMessageProxy.getChatMessageAtIndex(index)
|
||||||
|
// if (chatMessage && !chatMessage.core.isRead) chatMessage.core.lMarkAsRead()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
model: ChatMessageProxy {
|
model: ChatMessageProxy {
|
||||||
id: chatMessageProxy
|
id: chatMessageProxy
|
||||||
chatGui: mainItem.chat
|
chatGui: mainItem.chat
|
||||||
|
onCountChanged: {
|
||||||
|
var indexToSelect = mainItem.currentIndex
|
||||||
|
mainItem.currentIndex = -1
|
||||||
|
mainItem.currentIndex = indexToSelect
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
header: Item {
|
header: Item {
|
||||||
|
|
@ -31,7 +59,7 @@ ListView {
|
||||||
chatMessage: modelData
|
chatMessage: modelData
|
||||||
property real maxWidth: Math.round(mainItem.width * (3/4))
|
property real maxWidth: Math.round(mainItem.width * (3/4))
|
||||||
// height: childrenRect.height
|
// height: childrenRect.height
|
||||||
// width: childrenRect.width
|
width: mainItem.width
|
||||||
property var previousIndex: index - 1
|
property var previousIndex: index - 1
|
||||||
property var previousFromAddress: chatMessageProxy.getChatMessageAtIndex(index-1)?.core.fromAddress
|
property var previousFromAddress: chatMessageProxy.getChatMessageAtIndex(index-1)?.core.fromAddress
|
||||||
backgroundColor: isRemoteMessage ? DefaultStyle.main2_100 : DefaultStyle.main1_100
|
backgroundColor: isRemoteMessage ? DefaultStyle.main2_100 : DefaultStyle.main1_100
|
||||||
|
|
@ -52,7 +80,7 @@ ListView {
|
||||||
bottomPadding: Math.round(5 * DefaultStyle.dp)
|
bottomPadding: Math.round(5 * DefaultStyle.dp)
|
||||||
background: Rectangle {
|
background: Rectangle {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
color: mainItem.panelColor
|
color: mainItem.backgroundColor
|
||||||
}
|
}
|
||||||
contentItem: RowLayout {
|
contentItem: RowLayout {
|
||||||
id: composeLayout
|
id: composeLayout
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,7 @@ RowLayout {
|
||||||
ChatMessagesListView {
|
ChatMessagesListView {
|
||||||
id: chatMessagesListView
|
id: chatMessagesListView
|
||||||
height: contentHeight
|
height: contentHeight
|
||||||
backgroundColor: panelColor
|
backgroundColor: splitPanel.panelColor
|
||||||
width: parent.width - anchors.leftMargin - anchors.rightMargin
|
width: parent.width - anchors.leftMargin - anchors.rightMargin
|
||||||
chat: mainItem.chat
|
chat: mainItem.chat
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
|
|
@ -146,8 +146,8 @@ RowLayout {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
leftPadding: Math.round(15 * DefaultStyle.dp)
|
leftPadding: Math.round(15 * DefaultStyle.dp)
|
||||||
rightPadding: Math.round(15 * DefaultStyle.dp)
|
rightPadding: Math.round(15 * DefaultStyle.dp)
|
||||||
topPadding: Math.round(16 * DefaultStyle.dp)
|
topPadding: Math.round(15 * DefaultStyle.dp)
|
||||||
bottomPadding: Math.round(16 * DefaultStyle.dp)
|
bottomPadding: Math.round(15 * DefaultStyle.dp)
|
||||||
background: Rectangle {
|
background: Rectangle {
|
||||||
id: inputBackground
|
id: inputBackground
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
@ -188,9 +188,15 @@ RowLayout {
|
||||||
height: sendingAreaFlickable.height
|
height: sendingAreaFlickable.height
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
wrapMode: TextEdit.WordWrap
|
||||||
//: Say something… : placeholder text for sending message text area
|
//: Say something… : placeholder text for sending message text area
|
||||||
placeholderText: qsTr("Dites quelque chose…")
|
placeholderText: qsTr("Dites quelque chose…")
|
||||||
placeholderTextColor: DefaultStyle.main2_400
|
placeholderTextColor: DefaultStyle.main2_400
|
||||||
|
color: DefaultStyle.main2_700
|
||||||
|
font {
|
||||||
|
pixelSize: Typography.p1.pixelSize
|
||||||
|
weight: Typography.p1.weight
|
||||||
|
}
|
||||||
onCursorRectangleChanged: sendingAreaFlickable.ensureVisible(cursorRectangle)
|
onCursorRectangleChanged: sendingAreaFlickable.ensureVisible(cursorRectangle)
|
||||||
property string previousText
|
property string previousText
|
||||||
Component.onCompleted: previousText = text
|
Component.onCompleted: previousText = text
|
||||||
|
|
|
||||||
|
|
@ -684,8 +684,8 @@ AbstractMainPage {
|
||||||
KeyNavigation.up: deletePopup
|
KeyNavigation.up: deletePopup
|
||||||
KeyNavigation.down: joinButton
|
KeyNavigation.down: joinButton
|
||||||
onClicked: {
|
onClicked: {
|
||||||
UtilsCpp.copyToClipboard(mainItem.selectedConference.core.uri)
|
var success = UtilsCpp.copyToClipboard(mainItem.selectedConference.core.uri)
|
||||||
UtilsCpp.showInformationPopup(qsTr("saved"),
|
if (success) UtilsCpp.showInformationPopup(qsTr("saved"),
|
||||||
//: "Adresse de la réunion copiée"
|
//: "Adresse de la réunion copiée"
|
||||||
qsTr("meeting_address_copied_to_clipboard_toast"))
|
qsTr("meeting_address_copied_to_clipboard_toast"))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -113,7 +113,8 @@
|
||||||
color: {
|
color: {
|
||||||
normal: Linphone.DefaultStyle.grey_500,
|
normal: Linphone.DefaultStyle.grey_500,
|
||||||
hovered: Linphone.DefaultStyle.grey_600,
|
hovered: Linphone.DefaultStyle.grey_600,
|
||||||
pressed: Linphone.DefaultStyle.main2_400
|
pressed: Linphone.DefaultStyle.main2_400,
|
||||||
|
hovered: Linphone.DefaultStyle.main2_400
|
||||||
},
|
},
|
||||||
text: {
|
text: {
|
||||||
normal: Linphone.DefaultStyle.grey_0,
|
normal: Linphone.DefaultStyle.grey_0,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue