diff --git a/resources/icons/Preview_Black_24dp.svg b/resources/icons/Preview_Black_24dp.svg
new file mode 100644
index 00000000..6f674ba2
--- /dev/null
+++ b/resources/icons/Preview_Black_24dp.svg
@@ -0,0 +1,14 @@
+
+
+
diff --git a/resources/icons/Shift-Enter_Black_24dp.svg b/resources/icons/Shift-Enter_Black_24dp.svg
new file mode 100644
index 00000000..4c54a845
--- /dev/null
+++ b/resources/icons/Shift-Enter_Black_24dp.svg
@@ -0,0 +1,7 @@
+
+
+
diff --git a/resources/icons/more_Menu_Black_24dp.svg b/resources/icons/more_Menu_Black_24dp.svg
new file mode 100644
index 00000000..02a4b156
--- /dev/null
+++ b/resources/icons/more_Menu_Black_24dp.svg
@@ -0,0 +1,13 @@
+
+
+
diff --git a/src/app/appsettingsmanager.h b/src/app/appsettingsmanager.h
index eba192e3..7397df79 100644
--- a/src/app/appsettingsmanager.h
+++ b/src/app/appsettingsmanager.h
@@ -60,6 +60,7 @@ extern const QString defaultDownloadPath;
X(PositionShareLimit, true) \
X(FlipSelf, true) \
X(ShowMardownOption, false) \
+ X(ChatViewEnterIsNewLine, false) \
X(ShowSendOption, false)
/*
diff --git a/src/app/commoncomponents/MarkdownPopup.qml b/src/app/commoncomponents/MarkdownPopup.qml
index 67c72737..2411fc1b 100644
--- a/src/app/commoncomponents/MarkdownPopup.qml
+++ b/src/app/commoncomponents/MarkdownPopup.qml
@@ -67,7 +67,7 @@ Popup {
focusPolicy: Qt.TabFocus
normalColor: JamiTheme.chatViewFooterListColor
- imageColor: JamiTheme.chatViewFooterImgColor
+ imageColor: JamiTheme.chatViewFooterImgHoverColor
hoveredColor: JamiTheme.showMoreButtonOpenColor
pressedColor: hoveredColor
diff --git a/src/app/commoncomponents/SharePopup.qml b/src/app/commoncomponents/SharePopup.qml
new file mode 100644
index 00000000..b2dfe05f
--- /dev/null
+++ b/src/app/commoncomponents/SharePopup.qml
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2023 Savoir-faire Linux Inc.
+ *
+ * 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
+import QtQuick.Layouts
+import QtQuick.Controls
+import Qt.labs.platform
+import Qt5Compat.GraphicalEffects
+import net.jami.Models 1.1
+import net.jami.Adapters 1.1
+import net.jami.Constants 1.1
+import "../mainview/components"
+
+Popup {
+ id: root
+ padding: 0
+ property list menuMoreButton
+
+ height: childrenRect.height
+ width: childrenRect.width
+
+ focus: true
+ closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
+
+ Rectangle {
+ id: rect
+
+ color: JamiTheme.primaryBackgroundColor
+ border.color: JamiTheme.chatViewFooterRectangleBorderColor
+ border.width: 2
+ radius: 5
+ height: listViewMoreButton.childrenRect.height + 16
+ width: listViewMoreButton.childrenRect.width + 16
+
+ ListView {
+ id: listViewMoreButton
+
+ anchors.centerIn: parent
+ orientation: ListView.Vertical
+
+ spacing: 5
+
+ width: contentItem.childrenRect.width
+ height: contentHeight
+
+ model: menuMoreButton
+
+ Rectangle {
+ z: -1
+ anchors.fill: parent
+ color: "transparent"
+ }
+
+ delegate: ItemDelegate {
+ width: control.width
+ height: control.height
+
+ AbstractButton {
+ id: control
+
+ anchors.centerIn: parent
+ height: JamiTheme.chatViewFooterRealButtonSize + 10
+
+ text: modelData.toolTip
+
+ contentItem: RowLayout {
+ Rectangle {
+ id: image
+ width: 26
+ height: 26
+ radius: 5
+ color: JamiTheme.transparentColor
+ ResponsiveImage {
+ anchors.fill: parent
+ source: modelData.iconSrc
+ color: control.hovered ? JamiTheme.chatViewFooterImgHoverColor : JamiTheme.chatViewFooterImgColor
+ }
+ }
+ Text {
+ text: control.text
+ color: control.hovered ? JamiTheme.chatViewFooterImgHoverColor : "#7f7f7f"
+ }
+ }
+ background: Rectangle {
+ color: control.hovered ? JamiTheme.showMoreButtonOpenColor : JamiTheme.transparentColor
+ }
+
+ action: modelData
+
+ onClicked: {
+ root.close();
+ }
+ }
+ }
+ }
+ }
+
+ background: Rectangle {
+ anchors.fill: parent
+ color: JamiTheme.transparentColor
+ radius: 5
+ z: -1
+ }
+
+ enter: Transition {
+ NumberAnimation {
+ properties: "opacity"
+ from: 0.0
+ to: 1.0
+ duration: JamiTheme.shortFadeDuration
+ }
+ }
+ exit: Transition {
+ NumberAnimation {
+ properties: "opacity"
+ from: 1.0
+ to: 0.0
+ duration: JamiTheme.shortFadeDuration
+ }
+ }
+}
diff --git a/src/app/constant/JamiStrings.qml b/src/app/constant/JamiStrings.qml
index 251adc7b..5ca12f22 100644
--- a/src/app/constant/JamiStrings.qml
+++ b/src/app/constant/JamiStrings.qml
@@ -790,8 +790,8 @@ Item {
property string addEmoji: qsTr("Add emoji")
property string moreEmojis: qsTr("more emojis")
property string sendFile: qsTr("Send file")
- property string leaveAudioMessage: qsTr("Leave audio message")
- property string leaveVideoMessage: qsTr("Leave video message")
+ property string leaveAudioMessage: qsTr("Audio message")
+ property string leaveVideoMessage: qsTr("Video message")
property string showMore: qsTr("Show more")
property string showLess: qsTr("Show less")
@@ -806,7 +806,8 @@ Item {
property string orderedList: qsTr("Ordered list")
property string showFormating: qsTr("Show Formating")
property string hideFormating: qsTr("Hide Formating")
-
+ property string shiftEnterNewLine: qsTr("Press Shift+Enter to insert a new line")
+ property string enterNewLine: qsTr("Press Enter to insert a new line")
property string send: qsTr("Send")
property string remove: qsTr("Remove")
property string replyTo: qsTr("Reply to")
diff --git a/src/app/constant/JamiTheme.qml b/src/app/constant/JamiTheme.qml
index 2974c991..d0b082eb 100644
--- a/src/app/constant/JamiTheme.qml
+++ b/src/app/constant/JamiTheme.qml
@@ -219,6 +219,7 @@ Item {
property color fileInTimestampColor: darkTheme ? "#999" : "#555"
property color chatviewBgColor: darkTheme ? bgDarkMode_ : whiteColor
property color bgInvitationRectColor: darkTheme ? "#222222" : whiteColor
+ property color messageBarPlaceholderTextColor: darkTheme ? "#909090" : "#7e7e7e"
property color placeholderTextColor: darkTheme ? "#7a7a7a" : "black" //Qt.rgba(0, 0, 0, 0.2)
property color placeholderTextColorWhite: "#cccccc"
property color inviteHoverColor: darkTheme ? blackColor : whiteColor
@@ -233,11 +234,14 @@ Item {
// ChatView Footer
property color chatViewFooterListColor: darkTheme ? blackColor : "#E5E5E5"
- property color chatViewFooterImgColor: darkTheme ? whiteColor : blackColor
- property color showMoreButtonOpenColor: darkTheme ? "#123F4A" : "#CCCCCC"
+ property color chatViewFooterImgHoverColor: darkTheme ? whiteColor : blackColor
+ property color chatViewFooterImgColor: darkTheme ? "#909090" : "#7e7e7e"
+ property color chatViewFooterImgDisableColor: darkTheme ? "#4d4d4d" : "#cbcbcb"
+ property color showMoreButtonOpenColor: darkTheme ? "#4d4d4d" : "#e5e5e5"
property color chatViewFooterSeparateLineColor: darkTheme ? "#5c5c5c" : "#929292"
property color chatViewFooterSendButtonColor: darkTheme ? "#03B9E9" : "#005699"
property color chatViewFooterSendButtonImgColor: darkTheme ? blackColor : whiteColor
+ property color chatViewFooterRectangleBorderColor: darkTheme ? "#4d4d4d" : "#e5e5e5"
// ChatView Header
property real chatViewHeaderButtonRadius: 5
@@ -299,7 +303,7 @@ Item {
// Sizes
property real mainViewLeftPaneMinWidth: 300
- property real mainViewPaneMinWidth: 430
+ property real mainViewPaneMinWidth: 490
property real qrCodeImageSize: 256
property real splitViewHandlePreferredWidth: 4
property real indicatorFontSize: calcSize(6)
@@ -433,14 +437,14 @@ Item {
property real chatViewHairLineSize: 1
property real chatViewMaximumWidth: 900
property real chatViewHeaderPreferredHeight: 64
- property real chatViewFooterPreferredHeight: 50
- property real chatViewFooterMaximumHeight: 280
+ property real chatViewFooterPreferredHeight: 35
+ property real chatViewFooterMaximumHeight: 315
property real chatViewFooterRowSpacing: 4
property real chatViewFooterButtonSize: 36
property real chatViewFooterRealButtonSize: 26
property real chatViewFooterButtonIconSize: 48
property real chatViewFooterButtonRadius: 5
- property real chatViewFooterTextAreaMaximumHeight: 130
+ property real chatViewFooterTextAreaMaximumHeight: 260
property real chatViewScrollToBottomButtonBottomMargin: 8
property real usernameBlockFontSize: calcSize(12)
@@ -581,7 +585,7 @@ Item {
property int keyboardShortcutDelegateSize: 50
// Main application spec
- property real mainViewMinWidth: 430
+ property real mainViewMinWidth: 490
property real mainViewMinHeight: 500
property real wizardViewMinWidth: 500
diff --git a/src/app/mainview/components/ChatView.qml b/src/app/mainview/components/ChatView.qml
index 3005fca0..57422b0c 100644
--- a/src/app/mainview/components/ChatView.qml
+++ b/src/app/mainview/components/ChatView.qml
@@ -263,6 +263,7 @@ Rectangle {
currentIndex: CurrentConversation.isRequest || CurrentConversation.needsSyncing
Loader {
+ id: loader
active: CurrentConversation.id !== ""
sourceComponent: MessageListView {
DropArea {
@@ -302,6 +303,10 @@ Rectangle {
return CurrentConversation.isSwarm || CurrentConversation.isTemporary;
}
+ onHeightChanged: {
+ Qt.callLater(loader.item.scrollToBottom);
+ }
+
Layout.alignment: Qt.AlignHCenter
Layout.fillWidth: true
Layout.preferredHeight: implicitHeight
diff --git a/src/app/mainview/components/ChatViewFooter.qml b/src/app/mainview/components/ChatViewFooter.qml
index f388fd6f..8fe83bd3 100644
--- a/src/app/mainview/components/ChatViewFooter.qml
+++ b/src/app/mainview/components/ChatViewFooter.qml
@@ -25,10 +25,10 @@ import "../../commoncomponents"
Rectangle {
id: root
-
property alias textInput: messageBar.textAreaObj
property string previousConvId
property string previousAccountId
+ property bool showTypo: messageBar.showTypo
function setFilePathsToSend(filePaths) {
for (var index = 0; index < filePaths.length; ++index) {
@@ -96,7 +96,6 @@ Rectangle {
ColumnLayout {
id: footerColumnLayout
-
anchors.centerIn: root
width: root.width
@@ -130,6 +129,8 @@ Rectangle {
Layout.alignment: Qt.AlignHCenter
Layout.preferredWidth: footerColumnLayout.width
+ Layout.preferredHeight: height
+
property var emojiPicker
Connections {
@@ -156,11 +157,7 @@ Rectangle {
}
function setXposition() {
- if (UtilsAdapter.isRTL) {
- return messageBar.width - JamiTheme.emojiPickerWidth;
- } else {
- return 0;
- }
+ return messageBar.width - JamiTheme.emojiPickerWidth;
}
function setYposition() {
diff --git a/src/app/mainview/components/ChatViewHeader.qml b/src/app/mainview/components/ChatViewHeader.qml
index 79b6bc7d..dbf46c8c 100644
--- a/src/app/mainview/components/ChatViewHeader.qml
+++ b/src/app/mainview/components/ChatViewHeader.qml
@@ -93,9 +93,6 @@ Rectangle {
source: JamiResources.back_24dp_svg
toolTipText: CurrentConversation.inCall ? JamiStrings.backCall : JamiStrings.hideChat
- normalColor: JamiTheme.chatviewBgColor
- imageColor: JamiTheme.chatviewButtonColor
-
onClicked: root.backClicked()
}
diff --git a/src/app/mainview/components/JamiPushButton.qml b/src/app/mainview/components/JamiPushButton.qml
index 9cb2929f..80e11131 100644
--- a/src/app/mainview/components/JamiPushButton.qml
+++ b/src/app/mainview/components/JamiPushButton.qml
@@ -24,5 +24,5 @@ PushButton {
radius: JamiTheme.chatViewHeaderButtonRadius
normalColor: JamiTheme.chatviewBgColor
- imageColor: JamiTheme.chatviewButtonColor
+ imageColor: hovered ? JamiTheme.chatviewButtonColor : JamiTheme.chatViewFooterImgColor
}
diff --git a/src/app/mainview/components/MessageBar.qml b/src/app/mainview/components/MessageBar.qml
index 117f6552..5ca657a2 100644
--- a/src/app/mainview/components/MessageBar.qml
+++ b/src/app/mainview/components/MessageBar.qml
@@ -25,9 +25,14 @@ import net.jami.Enums 1.1
import net.jami.Constants 1.1
import "../../commoncomponents"
-ColumnLayout {
+Rectangle {
id: root
+ Layout.fillWidth: true
+ Layout.leftMargin: marginSize
+ Layout.rightMargin: marginSize
+ Layout.bottomMargin: marginSize
+
property alias text: textArea.text
property var textAreaObj: textArea
property real marginSize: JamiTheme.messageBarMarginSize
@@ -35,10 +40,15 @@ ColumnLayout {
property bool animate: false
property bool showDefault: !UtilsAdapter.getAppValue(Settings.Key.ShowSendOption)
property bool showTypo: UtilsAdapter.getAppValue(Settings.Key.ShowMardownOption)
+ property bool chatViewEnterIsNewLine: UtilsAdapter.getAppValue(Settings.Key.ChatViewEnterIsNewLine)
property bool showTypoSecond: false
+ property bool showPreview: false
+ property bool multiLine: textArea.tooMuch
property int messageBarLayoutMaximumWidth: 486
+ readonly property bool isFullScreen: visibility === Window.FullScreen
+
signal sendMessageButtonClicked
signal sendFileButtonClicked
signal audioRecordMessageButtonClicked
@@ -46,827 +56,997 @@ ColumnLayout {
signal showMapClicked
signal emojiButtonClicked
- spacing: 5
+ color: JamiTheme.transparentColor
+ height: showTypo || multiLine ? textArea.height + 25 + 3 * marginSize : textArea.height + marginSize
- Rectangle {
- id: messageBarHairLine
+ ComboBox {
+ id: showMoreButton
+ width: JamiTheme.chatViewFooterButtonSize
+ height: JamiTheme.chatViewFooterButtonSize
- Layout.alignment: Qt.AlignTop | Qt.AlignHCenter
- Layout.preferredHeight: JamiTheme.chatViewHairLineSize
- Layout.fillWidth: true
+ anchors.leftMargin: marginSize
+ anchors.bottom: parent.bottom
+ anchors.bottomMargin: marginSize / 2
- color: JamiTheme.tabbarBorderColor
- }
-
- MessageBarTextArea {
- id: textArea
-
- objectName: "messageBarTextArea"
-
- // forward activeFocus to the actual text area object
- onActiveFocusChanged: {
- if (activeFocus)
- textAreaObj.forceActiveFocus();
+ background: Rectangle {
+ implicitWidth: showMoreButton.width
+ implicitHeight: showMoreButton.height
+ radius: 5
+ color: JamiTheme.transparentColor
}
- placeholderText: JamiStrings.writeTo.arg(CurrentConversation.title)
+ MaterialToolTip {
+ id: toolTipMoreButton
- Layout.alignment: Qt.AlignVCenter
- Layout.fillWidth: true
- Layout.leftMargin: marginSize / 2
- Layout.rightMargin: marginSize / 2
- Layout.preferredHeight: {
- return JamiTheme.chatViewFooterPreferredHeight > contentHeight ? JamiTheme.chatViewFooterPreferredHeight : contentHeight;
+ parent: showMoreButton
+ visible: showMoreButton.hovered && (text.length > 0)
+ delay: Qt.styleHints.mousePressAndHoldInterval
+ text: JamiStrings.showMore
}
- Layout.maximumHeight: JamiTheme.chatViewFooterTextAreaMaximumHeight - marginSize / 2
- onSendMessagesRequired: root.sendMessageButtonClicked()
- onTextChanged: MessagesAdapter.userIsComposing(text ? true : false)
+ indicator: ResponsiveImage {
- property var markdownShortCut: {
- "Bold": function () {
- listViewTypoFirst.itemAtIndex(0).action.triggered();
- },
- "Italic": function () {
- listViewTypoFirst.itemAtIndex(1).action.triggered();
- },
- "Barre": function () {
- listViewTypoFirst.itemAtIndex(2).action.triggered();
- },
- "Heading": function () {
- listViewTypoFirst.itemAtIndex(3).action.triggered();
- },
- "Link": function () {
- listViewTypoSecond.itemAtIndex(0).action.triggered();
- },
- "Code": function () {
- listViewTypoSecond.itemAtIndex(1).action.triggered();
- },
- "Quote": function () {
- listViewTypoSecond.itemAtIndex(2).action.triggered();
- },
- "Unordered list": function () {
- listViewTypoSecond.itemAtIndex(3).action.triggered();
- },
- "Ordered list": function () {
- listViewTypoSecond.itemAtIndex(4).action.triggered();
+ width: 25
+ height: 25
+
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.horizontalCenter: parent.horizontalCenter
+
+ source: JamiResources.more_menu_black_24dp_svg
+
+ color: JamiTheme.chatViewFooterImgColor
+ }
+
+ onHoveredChanged: {
+ if (!sharePopup.opened) {
+ showMoreButton.indicator.color = hovered ? JamiTheme.chatViewFooterImgHoverColor : JamiTheme.chatViewFooterImgColor;
+ showMoreButton.background.color = hovered ? JamiTheme.hoveredButtonColor : JamiTheme.transparentColor;
}
}
- Shortcut {
- sequence: "Ctrl+B"
- context: Qt.ApplicationShortcut
- onActivated: textArea.markdownShortCut["Bold"]()
- }
+ popup: SharePopup {
+ id: sharePopup
+ y: -150
+ x: -20
- Shortcut {
- sequence: "Ctrl+I"
- context: Qt.ApplicationShortcut
- onActivated: textArea.markdownShortCut["Italic"]()
- }
-
- Shortcut {
- sequence: "Shift+Alt+X"
- context: Qt.ApplicationShortcut
- onActivated: textArea.markdownShortCut["Barre"]()
- }
-
- Shortcut {
- sequence: "Ctrl+Alt+H"
- context: Qt.ApplicationShortcut
- onActivated: textArea.markdownShortCut["Heading"]()
- }
-
- Shortcut {
- sequence: "Ctrl+Alt+K"
- context: Qt.ApplicationShortcut
- onActivated: textArea.markdownShortCut["Link"]()
- }
-
- Shortcut {
- sequence: "Ctrl+Alt+C"
- context: Qt.ApplicationShortcut
- onActivated: textArea.markdownShortCut["Code"]()
- }
-
- Shortcut {
- sequence: "Shift+Alt+9"
- context: Qt.ApplicationShortcut
- onActivated: textArea.markdownShortCut["Quote"]()
- }
-
- Shortcut {
- sequence: "Shift+Alt+8"
- context: Qt.ApplicationShortcut
- onActivated: textArea.markdownShortCut["Unordered list"]()
- }
-
- Shortcut {
- sequence: "Shift+Alt+7"
- context: Qt.ApplicationShortcut
- onActivated: textArea.markdownShortCut["Ordered list"]()
+ menuMoreButton: listViewMoreButton.menuMoreButton
}
}
- Item {
- id: messageBar
- Layout.fillWidth: true
- Layout.preferredHeight: JamiTheme.chatViewFooterButtonSize
- Layout.leftMargin: marginSize
- Layout.bottomMargin: marginSize
+ Connections {
+ target: sharePopup
+ function onOpenedChanged() {
+ showMoreButton.indicator.color = (showMoreButton.parent && showMoreButton.parent.hovered) || (sharePopup != null && sharePopup.opened) ? JamiTheme.chatViewFooterImgHoverColor : JamiTheme.chatViewFooterImgColor;
+ showMoreButton.background.color = (showMoreButton.parent && showMoreButton.parent.hovered) || sharePopup.opened ? JamiTheme.hoveredButtonColor : JamiTheme.transparentColor;
+ }
+ }
+
+ Rectangle {
+ id: rectangle
+
+ anchors.top: parent.top
+ anchors.left: showMoreButton.right
+ anchors.right: sendButtonRow.left
+ anchors.rightMargin: marginSize
+ anchors.leftMargin: marginSize
+
+ radius: 5
+ color: JamiTheme.transparentColor
+ border.color: JamiTheme.chatViewFooterRectangleBorderColor
+ border.width: 2
onWidthChanged: {
- if (width < messageBarRowLayout.width + sendButtonRow.width + 2 * JamiTheme.preferredMarginSize) {
+ height = Qt.binding(() => root.height);
+ if (width < 468) {
showTypoSecond = false;
} else {
- if (width > 2 * messageBarRowLayout.width) {
+ if (width >= 468) {
showTypoSecond = true;
}
}
}
- RowLayout {
- id: messageBarRowLayout
+ GridLayout {
+ id: rowLayout
- spacing: JamiTheme.chatViewFooterRowSpacing
- anchors.left: parent.left
+ columns: 2
+ rows: 2
+ columnSpacing: 0
+ rowSpacing: 0
- Row {
+ anchors.fill: parent
- PushButton {
- id: typoButton
+ MessageBarTextArea {
+ id: textArea
- preferredSize: JamiTheme.chatViewFooterButtonSize
- imageContainerWidth: 24
- imageContainerHeight: 24
+ objectName: "messageBarTextArea"
+ maxWidth: rectangle.width - messageBarRowLayout.width - 31
- radius: JamiTheme.chatViewFooterButtonRadius
+ enabled: !showPreview
- toolTipText: showTypo ? JamiStrings.hideFormating : JamiStrings.showFormating
- source: JamiResources.text_edit_black_24dp_svg
+ Layout.row: showTypo || multiLine ? 0 : 1
+ Layout.column: showTypo || multiLine ? 0 : 0
+ Layout.columnSpan: showTypo || multiLine ? 2 : 1
- normalColor: !showTypo ? JamiTheme.chatViewFooterListColor : JamiTheme.showMoreButtonOpenColor
- imageColor: JamiTheme.chatViewFooterImgColor
- pressedColor: JamiTheme.showMoreButtonOpenColor
- hoveredColor: JamiTheme.showMoreButtonOpenColor
+ // forward activeFocus to the actual text area object
+ onActiveFocusChanged: {
+ if (activeFocus)
+ textAreaObj.forceActiveFocus();
+ }
- onClicked: {
- showTypo = !showTypo;
- if (messageBar.width < messageBarLayoutMaximumWidth + sendButtonRow.width + 2 * JamiTheme.preferredMarginSize)
- showTypoSecond = false;
- if (!showDefault)
- showDefault = true;
- UtilsAdapter.setAppValue(Settings.Key.ShowMardownOption, showTypo);
- UtilsAdapter.setAppValue(Settings.Key.ShowSendOption, !showDefault);
- }
+ placeholderText: JamiStrings.writeTo.arg(CurrentConversation.title)
- Rectangle {
- visible: showTypo
+ Layout.alignment: showTypo ? Qt.AlignLeft | Qt.AlignBottom : Qt.AlignBottom
+ Layout.fillWidth: true
+ Layout.leftMargin: marginSize / 2
+ Layout.topMargin: marginSize / 2
+ Layout.bottomMargin: marginSize / 2
+ Layout.rightMargin: marginSize / 2
+ Layout.preferredHeight: {
+ JamiTheme.chatViewFooterPreferredHeight > contentHeight ? JamiTheme.chatViewFooterPreferredHeight : contentHeight;
+ }
+ Layout.maximumHeight: JamiTheme.chatViewFooterTextAreaMaximumHeight - marginSize / 2
- anchors.fill: parent
- anchors.leftMargin: 3
- anchors.rightMargin: -5
- color: JamiTheme.showMoreButtonOpenColor
- z: -2
+ onSendMessagesRequired: sendMessageButtonClicked()
+ onTextChanged: MessagesAdapter.userIsComposing(text ? true : false)
+
+ property var markdownShortCut: {
+ "Bold": function () {
+ listViewTypoFirst.itemAtIndex(0).action.triggered();
+ },
+ "Italic": function () {
+ listViewTypoFirst.itemAtIndex(1).action.triggered();
+ },
+ "Barre": function () {
+ listViewTypoFirst.itemAtIndex(2).action.triggered();
+ },
+ "Heading": function () {
+ listViewTypoFirst.itemAtIndex(3).action.triggered();
+ },
+ "Link": function () {
+ listViewTypoSecond.itemAtIndex(0).action.triggered();
+ },
+ "Code": function () {
+ listViewTypoSecond.itemAtIndex(1).action.triggered();
+ },
+ "Quote": function () {
+ listViewTypoSecond.itemAtIndex(2).action.triggered();
+ },
+ "Unordered list": function () {
+ listViewTypoSecond.itemAtIndex(3).action.triggered();
+ },
+ "Ordered list": function () {
+ listViewTypoSecond.itemAtIndex(4).action.triggered();
+ },
+ "Enter is new line": function () {
+ listViewTypoSecond.itemAtIndex(5).action.triggered();
}
}
- Row {
- id: listViewTypo
- height: JamiTheme.chatViewFooterButtonSize
+ Shortcut {
+ sequence: "Ctrl+B"
+ context: Qt.ApplicationShortcut
+ onActivated: textArea.markdownShortCut["Bold"]()
+ }
- function addStyle(text, start, end, char1, char2) {
- // get the selected text with markdown effect
- var selectedText = text.substring(start - char1.length, end + char2.length);
- if (selectedText.startsWith(char1) && selectedText.endsWith(char2)) {
- // If the selected text is already formatted with the given characters, remove them
- selectedText = text.substring(start, end);
- root.text = text.substring(0, start - char1.length) + selectedText + text.substring(end + char2.length);
- textArea.selectText(start - char1.length, end - char1.length);
- } else {
- // Otherwise, add the formatting characters to the selected text
- root.text = text.substring(0, start) + char1 + text.substring(start, end) + char2 + text.substring(end);
- textArea.selectText(start + char1.length, end + char1.length);
- }
- }
+ Shortcut {
+ sequence: "Ctrl+I"
+ context: Qt.ApplicationShortcut
+ onActivated: textArea.markdownShortCut["Italic"]()
+ }
- function addPrefixStyle(message, selectionStart, selectionEnd, delimiter, isOrderedList) {
+ Shortcut {
+ sequence: "Shift+Alt+X"
+ context: Qt.ApplicationShortcut
+ onActivated: textArea.markdownShortCut["Barre"]()
+ }
- //represents all the selected lines
- var multilineSelection;
- var newPrefix;
- var newSuffix;
- var newStartPos;
- var newEndPos;
- function nextIndexOf(text, char1, startPos) {
- return text.indexOf(char1, startPos + 1);
- }
+ Shortcut {
+ sequence: "Ctrl+Alt+H"
+ context: Qt.ApplicationShortcut
+ onActivated: textArea.markdownShortCut["Heading"]()
+ }
- //get the previous index of the multilineSelection text
- if (message[selectionStart] === "\n")
- newStartPos = message.lastIndexOf('\n', selectionStart - 1);
- else
- newStartPos = message.lastIndexOf('\n', selectionStart);
+ Shortcut {
+ sequence: "Ctrl+Alt+K"
+ context: Qt.ApplicationShortcut
+ onActivated: textArea.markdownShortCut["Link"]()
+ }
- //get the next index of the multilineSelection text
- if (message[selectionEnd] === "\n" || message[selectionEnd] === undefined)
- newEndPos = selectionEnd;
- else
- newEndPos = nextIndexOf(message, "\n", selectionEnd);
+ Shortcut {
+ sequence: "Ctrl+Alt+C"
+ context: Qt.ApplicationShortcut
+ onActivated: textArea.markdownShortCut["Code"]()
+ }
- //if the text is empty
- if (newStartPos === -1)
- newStartPos = 0;
- newPrefix = message.slice(0, newStartPos);
- multilineSelection = message.slice(newStartPos, newEndPos);
- newSuffix = message.slice(newEndPos);
- var isFirstLineSelected = !multilineSelection.startsWith('\n') || newPrefix === "";
- var getDelimiter_counter = 1;
- function getDelimiter() {
- return `${getDelimiter_counter++}. `;
- }
- function getHasCurrentMarkdown() {
- const linesQuantity = (multilineSelection.match(/\n/g) || []).length;
- const newLinesWithDelimitersQuantity = (multilineSelection.match(new RegExp(`\n${delimiter}`, 'g')) || []).length;
- if (newLinesWithDelimitersQuantity === linesQuantity && !isFirstLineSelected)
- return true;
- return linesQuantity === newLinesWithDelimitersQuantity && multilineSelection.startsWith(delimiter);
- }
- function getHasCurrentMarkdownBullet() {
- const linesQuantity = (multilineSelection.match(/\n/g) || []).length;
- const newLinesWithDelimitersQuantity = (multilineSelection.match(/\n\d+\. /g) || []).length;
- if (newLinesWithDelimitersQuantity === linesQuantity && !isFirstLineSelected)
- return true;
- return linesQuantity === newLinesWithDelimitersQuantity && (/^\d\. /).test(multilineSelection);
- }
- var newValue;
- var newStart;
- var newEnd;
- var count;
- var startPos;
- var multilineSelectionLength;
- if (!isOrderedList) {
- if (getHasCurrentMarkdown()) {
+ Shortcut {
+ sequence: "Shift+Alt+9"
+ context: Qt.ApplicationShortcut
+ onActivated: textArea.markdownShortCut["Quote"]()
+ }
- // clear first line from delimiter
- if (isFirstLineSelected)
- multilineSelection = multilineSelection.slice(delimiter.length);
- newValue = newPrefix + multilineSelection.replace(new RegExp(`\n${delimiter}`, 'g'), '\n') + newSuffix;
- count = 0;
- if (isFirstLineSelected)
- count++;
- count += (multilineSelection.match(/\n/g) || []).length;
- newStart = Math.max(selectionStart - delimiter.length, 0);
- newEnd = Math.max(selectionEnd - (delimiter.length * count), 0);
- } else {
- newValue = newPrefix + multilineSelection.replace(/\n/g, `\n${delimiter}`) + newSuffix;
- count = 0;
- if (isFirstLineSelected) {
- newValue = delimiter + newValue;
- count++;
- }
- count += (multilineSelection.match(new RegExp('\\n', 'g')) || []).length;
- newStart = selectionStart + delimiter.length;
- newEnd = selectionEnd + (delimiter.length * count);
- }
- } else if (getHasCurrentMarkdownBullet()) {
- if (message[selectionStart] === "\n")
- startPos = message.lastIndexOf('\n', selectionStart - 1) + 1;
- else
- startPos = message.lastIndexOf('\n', selectionStart) + 1;
- newStart = startPos;
- multilineSelection = multilineSelection.replace(/^\d+\.\s/gm, '');
- newValue = newPrefix + multilineSelection + newSuffix;
- multilineSelectionLength = multilineSelection.length;
+ Shortcut {
+ sequence: "Shift+Alt+8"
+ context: Qt.ApplicationShortcut
+ onActivated: textArea.markdownShortCut["Unordered list"]()
+ }
- //if the first line is not selected, we need to remove the first "\n" of multilineSelection
- if (newStart)
- multilineSelectionLength = multilineSelection.length - 1;
- newEnd = Math.max(newStart + multilineSelectionLength, 0);
- } else {
- if (message[selectionStart] === "\n")
- startPos = message.lastIndexOf('\n', selectionStart - 1) + 1;
- else
- startPos = message.lastIndexOf('\n', selectionStart) + 1;
- newStart = startPos;
-
- // if no text is selected
- if (selectionStart === selectionEnd)
- newStart = newStart + 3;
- if (isFirstLineSelected)
- multilineSelection = getDelimiter() + multilineSelection;
- const selectionArr = Array.from(multilineSelection);
- for (var i = 0; i < selectionArr.length; i++) {
- if (selectionArr[i] === '\n')
- selectionArr[i] = `\n${getDelimiter()}`;
- }
- multilineSelection = selectionArr.join('');
- newValue = newPrefix + multilineSelection + newSuffix;
- multilineSelectionLength = multilineSelection.length;
-
- //if the first line is not selected, we meed to remove the first "\n" of multilineSelection
- if (startPos)
- multilineSelectionLength = multilineSelection.length - 1;
- newEnd = Math.max(startPos + multilineSelectionLength, 0);
- }
- root.text = newValue;
- textArea.selectText(newStart, newEnd);
- }
-
- ListView {
- id: listViewTypoFirst
-
- objectName: "listViewTypoFirst"
-
- visible: width > 0
- width: showTypo ? contentWidth + 2 * leftMargin : 0
-
- Behavior on width {
- NumberAnimation {
- duration: JamiTheme.longFadeDuration / 2
- }
- }
-
- height: JamiTheme.chatViewFooterButtonSize
- orientation: ListView.Horizontal
- interactive: false
- leftMargin: 10
- rightMargin: 10
- spacing: 10
-
- Rectangle {
- anchors.fill: parent
- color: JamiTheme.chatViewFooterListColor
- z: -1
- }
-
- property list menuTypoActionsFirst: [
- Action {
- id: boldAction
- property var iconSrc: JamiResources.bold_black_24dp_svg
- property var shortcutText: JamiStrings.bold
- property string shortcutKey: "Ctrl+B"
-
- onTriggered: function clickAction() {
- listViewTypo.addStyle(root.text, textArea.selectionStart, textArea.selectionEnd, "**", "**");
- }
- },
- Action {
- id: italicAction
- property var iconSrc: JamiResources.italic_black_24dp_svg
- property var shortcutText: JamiStrings.italic
- property string shortcutKey: "Ctrl+I"
- onTriggered: function clickAction() {
- listViewTypo.addStyle(root.text, textArea.selectionStart, textArea.selectionEnd, "*", "*");
- }
- },
- Action {
- id: strikethroughAction
- property var iconSrc: JamiResources.s_barre_black_24dp_svg
- property var shortcutText: JamiStrings.strikethrough
- property string shortcutKey: "Shift+Alt+X"
- onTriggered: function clickAction() {
- listViewTypo.addStyle(root.text, textArea.selectionStart, textArea.selectionEnd, "~~", "~~");
- }
- },
- Action {
- id: titleAction
- property var iconSrc: JamiResources.title_black_24dp_svg
- property var shortcutText: JamiStrings.title
- property string shortcutKey: "Ctrl+Alt+H"
- onTriggered: function clickAction() {
- listViewTypo.addPrefixStyle(root.text, textArea.selectionStart, textArea.selectionEnd, "### ", false);
- }
- }
- ]
-
- model: menuTypoActionsFirst
-
- delegate: PushButton {
- anchors.verticalCenter: parent.verticalCenter
-
- preferredSize: JamiTheme.chatViewFooterRealButtonSize
- imageContainerWidth: 15
- imageContainerHeight: 15
- radius: 5
-
- toolTipText: modelData.shortcutText
- shortcutKey: modelData.shortcutKey
- hasShortcut: true
-
- source: modelData.iconSrc
- focusPolicy: Qt.TabFocus
-
- normalColor: JamiTheme.chatViewFooterListColor
- imageColor: JamiTheme.chatViewFooterImgColor
- hoveredColor: JamiTheme.showMoreButtonOpenColor
- pressedColor: hoveredColor
-
- action: modelData
- }
- }
-
- Rectangle {
-
- height: JamiTheme.chatViewFooterButtonSize
- color: JamiTheme.chatViewFooterListColor
- visible: width > 0
- width: showTypo && showTypoSecond ? 2 : 0
-
- Behavior on width {
- NumberAnimation {
- duration: JamiTheme.longFadeDuration / 2
- }
- }
-
- Rectangle {
- anchors.verticalCenter: parent.verticalCenter
- width: 2
- height: JamiTheme.chatViewFooterButtonSize / 2
- color: JamiTheme.chatViewFooterSeparateLineColor
- }
- }
-
- Rectangle {
- z: -1
- radius: 0
- color: JamiTheme.chatViewFooterListColor
- width: JamiTheme.chatViewFooterButtonSize
- height: JamiTheme.chatViewFooterButtonSize
-
- visible: showTypo && !showTypoSecond
-
- ComboBox {
- id: showMoreTypoButton
- width: JamiTheme.chatViewFooterRealButtonSize
- height: width
- anchors.verticalCenter: parent.verticalCenter
-
- MaterialToolTip {
- id: toolTip
-
- parent: showMoreTypoButton
- visible: showMoreTypoButton.hovered && (text.length > 0)
- delay: Qt.styleHints.mousePressAndHoldInterval
- text: JamiStrings.showMore
- }
-
- background: Rectangle {
- implicitWidth: showMoreTypoButton.width
- implicitHeight: showMoreTypoButton.height
- radius: 5
- color: showMoreTypoButton.popup.opened || showMoreTypoButton.hovered ? JamiTheme.showMoreButtonOpenColor : JamiTheme.chatViewFooterListColor
- }
-
- indicator: ResponsiveImage {
- containerHeight: 20
- containerWidth: 20
- width: 18
- height: 18
-
- anchors.verticalCenter: parent.verticalCenter
- anchors.horizontalCenter: parent.horizontalCenter
-
- source: JamiResources.more_vert_24dp_svg
-
- color: JamiTheme.chatViewFooterImgColor
- }
-
- popup: MarkdownPopup {
- y: 1.5 * parent.height
- x: -parent.width * 3
- width: 190
- height: JamiTheme.chatViewFooterButtonSize
-
- menuTypoActionsSecond: listViewTypoSecond.menuTypoActionsSecond
- }
- }
- }
-
- ListView {
- id: listViewTypoSecond
- visible: width > 0
- width: showTypo && showTypoSecond ? contentWidth + 2 * leftMargin : 0
-
- Behavior on width {
- NumberAnimation {
- duration: JamiTheme.longFadeDuration / 2
- }
- }
-
- height: JamiTheme.chatViewFooterButtonSize
- orientation: ListView.Horizontal
- interactive: false
- leftMargin: 10
- rightMargin: 10
- spacing: 10
-
- Rectangle {
- anchors.fill: parent
- color: JamiTheme.chatViewFooterListColor
- z: -1
- }
-
- property list menuTypoActionsSecond: [
- Action {
- id: linkAction
- property var iconSrc: JamiResources.link_web_black_24dp_svg
- property var shortcutText: JamiStrings.link
- property string shortcutKey: "Ctrl+Alt+K"
- onTriggered: function clickAction() {
- listViewTypo.addStyle(root.text, textArea.selectionStart, textArea.selectionEnd, "[", "](url)");
- }
- },
- Action {
- id: codeAction
- property var iconSrc: JamiResources.code_black_24dp_svg
- property var shortcutText: JamiStrings.code
- property string shortcutKey: "Ctrl+Alt+C"
- onTriggered: function clickAction() {
- listViewTypo.addStyle(root.text, textArea.selectionStart, textArea.selectionEnd, "```", "```");
- }
- },
- Action {
- id: quoteAction
- property var iconSrc: JamiResources.quote_black_24dp_svg
- property var shortcutText: JamiStrings.quote
- property string shortcutKey: "Shift+Alt+9"
- onTriggered: function clickAction() {
- listViewTypo.addPrefixStyle(root.text, textArea.selectionStart, textArea.selectionEnd, "> ", false);
- }
- },
- Action {
- id: unorderedListAction
- property var iconSrc: JamiResources.bullet_point_black_24dp_svg
- property var shortcutText: JamiStrings.unorderedList
- property string shortcutKey: "Shift+Alt+8"
- onTriggered: function clickAction() {
- listViewTypo.addPrefixStyle(root.text, textArea.selectionStart, textArea.selectionEnd, "- ", false);
- }
- },
- Action {
- id: orderedListAction
- property var iconSrc: JamiResources.bullet_number_black_24dp_svg
- property var shortcutText: JamiStrings.orderedList
- property string shortcutKey: "Shift+Alt+7"
- onTriggered: function clickAction() {
- listViewTypo.addPrefixStyle(root.text, textArea.selectionStart, textArea.selectionEnd, "", true);
- }
- }
- ]
-
- model: menuTypoActionsSecond
-
- delegate: PushButton {
- anchors.verticalCenter: parent.verticalCenter
-
- preferredSize: JamiTheme.chatViewFooterRealButtonSize
- imageContainerWidth: 20
- imageContainerHeight: 20
- radius: 5
-
- toolTipText: modelData.shortcutText
- shortcutKey: modelData.shortcutKey
- hasShortcut: true
- source: modelData.iconSrc
- focusPolicy: Qt.TabFocus
-
- normalColor: JamiTheme.chatViewFooterListColor
- imageColor: JamiTheme.chatViewFooterImgColor
- hoveredColor: JamiTheme.showMoreButtonOpenColor
- pressedColor: hoveredColor
-
- action: modelData
- }
- }
+ Shortcut {
+ sequence: "Shift+Alt+7"
+ context: Qt.ApplicationShortcut
+ onActivated: textArea.markdownShortCut["Ordered list"]()
}
}
Row {
+ id: messageBarRowLayout
- ListView {
- id: listViewAction
+ Layout.row: showTypo || multiLine ? 1 : 1
+ Layout.column: showTypo || multiLine ? 0 : 1
+ Layout.alignment: showTypo || multiLine ? Qt.AlignRight : Qt.AlignBottom
+ Layout.columnSpan: showTypo || multiLine ? 2 : 1
+ Layout.topMargin: marginSize / 2
+ Layout.rightMargin: marginSize / 2
- width: contentWidth + 2 * leftMargin
+ Row {
- Behavior on width {
- NumberAnimation {
- duration: JamiTheme.longFadeDuration / 2
- }
- }
+ anchors.bottom: parent.bottom
+ anchors.bottomMargin: marginSize / 2
- height: JamiTheme.chatViewFooterButtonSize
- orientation: ListView.Horizontal
- interactive: false
+ Row {
+ id: listViewTypo
+ height: JamiTheme.chatViewFooterButtonSize
- leftMargin: 10
- rightMargin: 10
- spacing: 10
-
- Rectangle {
- anchors.fill: parent
- color: JamiTheme.chatViewFooterListColor
- z: -1
- }
-
- property list menuActions: [
- Action {
- id: sendFile
- property var iconSrc: JamiResources.link_black_24dp_svg
- property var toolTip: JamiStrings.sendFile
- property bool show: true
- property bool needWebEngine: false
- property bool needVideoDevice: false
- property bool noSip: false
- onTriggered: function clickAction() {
- sendFileButtonClicked();
- }
- },
- Action {
- id: addEmoji
- property var iconSrc: JamiResources.emoji_black_24dp_svg
- property var toolTip: JamiStrings.addEmoji
- property bool show: true
- property bool needWebEngine: true
- property bool needVideoDevice: false
- property bool noSip: true
- onTriggered: function clickAction() {
- emojiButtonClicked();
- }
- },
- Action {
- id: leaveAudioMessage
- property var iconSrc: JamiResources.message_audio_black_24dp_svg
- property var toolTip: JamiStrings.leaveAudioMessage
- property bool show: false
- property bool needWebEngine: false
- property bool needVideoDevice: false
- property bool noSip: false
- onTriggered: function clickAction() {
- audioRecordMessageButtonClicked();
- }
- },
- Action {
- id: leaveVideoMessage
- property var iconSrc: JamiResources.message_video_black_24dp_svg
- property var toolTip: JamiStrings.leaveVideoMessage
- property bool show: false
- property bool needWebEngine: false
- property bool needVideoDevice: true
- property bool noSip: false
- onTriggered: function clickAction() {
- videoRecordMessageButtonClicked();
- }
- },
- Action {
- id: shareLocation
- property var iconSrc: JamiResources.localisation_sharing_send_pin_svg
- property var toolTip: JamiStrings.shareLocation
- property bool show: false
- property bool needWebEngine: true
- property bool needVideoDevice: false
- property bool noSip: false
- onTriggered: function clickAction() {
- showMapClicked();
+ function addStyle(text, start, end, char1, char2) {
+ // get the selected text with markdown effect
+ var selectedText = text.substring(start - char1.length, end + char2.length);
+ if (selectedText.startsWith(char1) && selectedText.endsWith(char2)) {
+ // If the selected text is already formatted with the given characters, remove them
+ selectedText = text.substring(start, end);
+ root.text = text.substring(0, start - char1.length) + selectedText + text.substring(end + char2.length);
+ textArea.selectText(start - char1.length, end - char1.length);
+ } else {
+ // Otherwise, add the formatting characters to the selected text
+ root.text = text.substring(0, start) + char1 + text.substring(start, end) + char2 + text.substring(end);
+ textArea.selectText(start + char1.length, end + char1.length);
}
}
- ]
- ListModel {
- id: listActions
- Component.onCompleted: {
- for (var i = 0; i < listViewAction.menuActions.length; i++) {
- append({
- "menuAction": listViewAction.menuActions[i]
- });
+ function addPrefixStyle(message, selectionStart, selectionEnd, delimiter, isOrderedList) {
+
+ //represents all the selected lines
+ var multilineSelection;
+ var newPrefix;
+ var newSuffix;
+ var newStartPos;
+ var newEndPos;
+ function nextIndexOf(text, char1, startPos) {
+ return text.indexOf(char1, startPos + 1);
+ }
+
+ //get the previous index of the multilineSelection text
+ if (message[selectionStart] === "\n")
+ newStartPos = message.lastIndexOf('\n', selectionStart - 1);
+ else
+ newStartPos = message.lastIndexOf('\n', selectionStart);
+
+ //get the next index of the multilineSelection text
+ if (message[selectionEnd] === "\n" || message[selectionEnd] === undefined)
+ newEndPos = selectionEnd;
+ else
+ newEndPos = nextIndexOf(message, "\n", selectionEnd);
+
+ //if the text is empty
+ if (newStartPos === -1)
+ newStartPos = 0;
+ newPrefix = message.slice(0, newStartPos);
+ multilineSelection = message.slice(newStartPos, newEndPos);
+ newSuffix = message.slice(newEndPos);
+ var isFirstLineSelected = !multilineSelection.startsWith('\n') || newPrefix === "";
+ var getDelimiter_counter = 1;
+ function getDelimiter() {
+ return `${getDelimiter_counter++}. `;
+ }
+ function getHasCurrentMarkdown() {
+ const linesQuantity = (multilineSelection.match(/\n/g) || []).length;
+ const newLinesWithDelimitersQuantity = (multilineSelection.match(new RegExp(`\n${delimiter}`, 'g')) || []).length;
+ if (newLinesWithDelimitersQuantity === linesQuantity && !isFirstLineSelected)
+ return true;
+ return linesQuantity === newLinesWithDelimitersQuantity && multilineSelection.startsWith(delimiter);
+ }
+ function getHasCurrentMarkdownBullet() {
+ const linesQuantity = (multilineSelection.match(/\n/g) || []).length;
+ const newLinesWithDelimitersQuantity = (multilineSelection.match(/\n\d+\. /g) || []).length;
+ if (newLinesWithDelimitersQuantity === linesQuantity && !isFirstLineSelected)
+ return true;
+ return linesQuantity === newLinesWithDelimitersQuantity && (/^\d\. /).test(multilineSelection);
+ }
+ var newValue;
+ var newStart;
+ var newEnd;
+ var count;
+ var startPos;
+ var multilineSelectionLength;
+ if (!isOrderedList) {
+ if (getHasCurrentMarkdown()) {
+
+ // clear first line from delimiter
+ if (isFirstLineSelected)
+ multilineSelection = multilineSelection.slice(delimiter.length);
+ newValue = newPrefix + multilineSelection.replace(new RegExp(`\n${delimiter}`, 'g'), '\n') + newSuffix;
+ count = 0;
+ if (isFirstLineSelected)
+ count++;
+ count += (multilineSelection.match(/\n/g) || []).length;
+ newStart = Math.max(selectionStart - delimiter.length, 0);
+ newEnd = Math.max(selectionEnd - (delimiter.length * count), 0);
+ } else {
+ newValue = newPrefix + multilineSelection.replace(/\n/g, `\n${delimiter}`) + newSuffix;
+ count = 0;
+ if (isFirstLineSelected) {
+ newValue = delimiter + newValue;
+ count++;
+ }
+ count += (multilineSelection.match(new RegExp('\\n', 'g')) || []).length;
+ newStart = selectionStart + delimiter.length;
+ newEnd = selectionEnd + (delimiter.length * count);
+ }
+ } else if (getHasCurrentMarkdownBullet()) {
+ if (message[selectionStart] === "\n")
+ startPos = message.lastIndexOf('\n', selectionStart - 1) + 1;
+ else
+ startPos = message.lastIndexOf('\n', selectionStart) + 1;
+ newStart = startPos;
+ multilineSelection = multilineSelection.replace(/^\d+\.\s/gm, '');
+ newValue = newPrefix + multilineSelection + newSuffix;
+ multilineSelectionLength = multilineSelection.length;
+
+ //if the first line is not selected, we need to remove the first "\n" of multilineSelection
+ if (newStart)
+ multilineSelectionLength = multilineSelection.length - 1;
+ newEnd = Math.max(newStart + multilineSelectionLength, 0);
+ } else {
+ if (message[selectionStart] === "\n")
+ startPos = message.lastIndexOf('\n', selectionStart - 1) + 1;
+ else
+ startPos = message.lastIndexOf('\n', selectionStart) + 1;
+ newStart = startPos;
+
+ // if no text is selected
+ if (selectionStart === selectionEnd)
+ newStart = newStart + 3;
+ if (isFirstLineSelected)
+ multilineSelection = getDelimiter() + multilineSelection;
+ const selectionArr = Array.from(multilineSelection);
+ for (var i = 0; i < selectionArr.length; i++) {
+ if (selectionArr[i] === '\n')
+ selectionArr[i] = `\n${getDelimiter()}`;
+ }
+ multilineSelection = selectionArr.join('');
+ newValue = newPrefix + multilineSelection + newSuffix;
+ multilineSelectionLength = multilineSelection.length;
+
+ //if the first line is not selected, we meed to remove the first "\n" of multilineSelection
+ if (startPos)
+ multilineSelectionLength = multilineSelection.length - 1;
+ newEnd = Math.max(startPos + multilineSelectionLength, 0);
+ }
+ root.text = newValue;
+ textArea.selectText(newStart, newEnd);
+ }
+
+ ListView {
+ id: listViewTypoFirst
+
+ objectName: "listViewTypoFirst"
+
+ visible: width > 0
+ width: showTypo ? contentWidth + 2 * leftMargin : 0
+
+ Behavior on width {
+ NumberAnimation {
+ duration: JamiTheme.longFadeDuration / 2
+ }
+ }
+
+ height: JamiTheme.chatViewFooterButtonSize
+ orientation: ListView.Horizontal
+ interactive: false
+ leftMargin: 5
+ rightMargin: 5
+ spacing: 5
+
+ property list menuTypoActionsFirst: [
+ Action {
+ id: boldAction
+ property var iconSrc: JamiResources.bold_black_24dp_svg
+ property var shortcutText: JamiStrings.bold
+ property string shortcutKey: "Ctrl+B"
+ onTriggered: function clickAction() {
+ listViewTypo.addStyle(root.text, textArea.selectionStart, textArea.selectionEnd, "**", "**");
+ }
+ },
+ Action {
+ id: italicAction
+ property var iconSrc: JamiResources.italic_black_24dp_svg
+ property var shortcutText: JamiStrings.italic
+ property string shortcutKey: "Ctrl+I"
+ onTriggered: function clickAction() {
+ listViewTypo.addStyle(root.text, textArea.selectionStart, textArea.selectionEnd, "*", "*");
+ }
+ },
+ Action {
+ id: strikethroughAction
+ property var iconSrc: JamiResources.s_barre_black_24dp_svg
+ property var shortcutText: JamiStrings.strikethrough
+ property string shortcutKey: "Shift+Alt+X"
+ onTriggered: function clickAction() {
+ listViewTypo.addStyle(root.text, textArea.selectionStart, textArea.selectionEnd, "~~", "~~");
+ }
+ },
+ Action {
+ id: titleAction
+ property var iconSrc: JamiResources.title_black_24dp_svg
+ property var shortcutText: JamiStrings.title
+ property string shortcutKey: "Ctrl+Alt+H"
+ onTriggered: function clickAction() {
+ listViewTypo.addPrefixStyle(root.text, textArea.selectionStart, textArea.selectionEnd, "### ", false);
+ }
+ },
+ Action {
+ id: linkAction
+ property var iconSrc: JamiResources.link_web_black_24dp_svg
+ property var shortcutText: JamiStrings.link
+ property string shortcutKey: "Ctrl+Alt+K"
+ onTriggered: function clickAction() {
+ listViewTypo.addStyle(root.text, textArea.selectionStart, textArea.selectionEnd, "[", "](url)");
+ }
+ },
+ Action {
+ id: codeAction
+ property var iconSrc: JamiResources.code_black_24dp_svg
+ property var shortcutText: JamiStrings.code
+ property string shortcutKey: "Ctrl+Alt+C"
+ onTriggered: function clickAction() {
+ listViewTypo.addStyle(root.text, textArea.selectionStart, textArea.selectionEnd, "```", "```");
+ }
+ }
+ ]
+
+ model: menuTypoActionsFirst
+
+ delegate: PushButton {
+ anchors.verticalCenter: parent.verticalCenter
+
+ preferredSize: JamiTheme.chatViewFooterRealButtonSize
+ imageContainerWidth: 15
+ imageContainerHeight: 15
+ radius: 5
+
+ hoverEnabled: !showPreview
+ enabled: !showPreview
+
+ toolTipText: modelData.shortcutText
+ shortcutKey: modelData.shortcutKey
+ hasShortcut: true
+
+ source: modelData.iconSrc
+ focusPolicy: Qt.TabFocus
+
+ normalColor: JamiTheme.transparentColor
+ imageColor: showPreview ? JamiTheme.chatViewFooterImgDisableColor : (hovered ? JamiTheme.chatViewFooterImgHoverColor : JamiTheme.chatViewFooterImgColor)
+ hoveredColor: JamiTheme.hoveredButtonColor
+ pressedColor: hoveredColor
+
+ action: modelData
+ }
+ }
+
+ Rectangle {
+
+ height: JamiTheme.chatViewFooterButtonSize
+ color: JamiTheme.transparentColor
+ visible: width > 0
+ width: showTypo && showTypoSecond ? 2 : 0
+
+ /*Behavior on width {
+ NumberAnimation {
+ duration: JamiTheme.longFadeDuration / 2
+ }
+ }*/
+ Rectangle {
+ anchors.verticalCenter: parent.verticalCenter
+ width: 2
+ height: JamiTheme.chatViewFooterButtonSize / 2
+ color: showPreview ? JamiTheme.chatViewFooterImgDisableColor : JamiTheme.chatViewFooterSeparateLineColor
+ }
+ }
+
+ Rectangle {
+ z: -1
+ radius: 0
+ color: JamiTheme.transparentColor
+ width: JamiTheme.chatViewFooterButtonSize
+ height: JamiTheme.chatViewFooterButtonSize
+
+ visible: showTypo && !showTypoSecond
+
+ ComboBox {
+ id: showMoreTypoButton
+ width: JamiTheme.chatViewFooterRealButtonSize
+ height: width
+ anchors.verticalCenter: parent.verticalCenter
+
+ enabled: !showPreview
+ hoverEnabled: !showPreview
+
+ MaterialToolTip {
+ id: toolTip
+
+ parent: showMoreTypoButton
+ visible: showMoreTypoButton.hovered && (text.length > 0)
+ delay: Qt.styleHints.mousePressAndHoldInterval
+ text: JamiStrings.showMore
+ }
+
+ background: Rectangle {
+ implicitWidth: showMoreTypoButton.width
+ implicitHeight: showMoreTypoButton.height
+ radius: 5
+ color: showPreview ? JamiTheme.transparentColor : (parent && parent.hovered ? JamiTheme.hoveredButtonColor : JamiTheme.transparentColor)
+ }
+
+ indicator: ResponsiveImage {
+ containerHeight: 20
+ containerWidth: 20
+ width: 18
+ height: 18
+
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.horizontalCenter: parent.horizontalCenter
+
+ source: JamiResources.more_vert_24dp_svg
+
+ color: showPreview ? JamiTheme.chatViewFooterImgDisableColor : (parent && parent.hovered ? JamiTheme.chatViewFooterImgHoverColor : JamiTheme.chatViewFooterImgColor)
+ }
+
+ popup: MarkdownPopup {
+ y: 1.5 * parent.height
+ x: -parent.width * 2
+ width: 155
+ height: JamiTheme.chatViewFooterButtonSize
+
+ menuTypoActionsSecond: listViewTypoSecond.menuTypoActionsSecond
+ }
+ }
+ }
+
+ ListView {
+ id: listViewTypoSecond
+ visible: width > 0
+ width: showTypo && showTypoSecond ? contentWidth + 2 * leftMargin : 0
+
+ height: JamiTheme.chatViewFooterButtonSize
+ orientation: ListView.Horizontal
+ interactive: false
+ leftMargin: 10
+ rightMargin: 10
+ spacing: 10
+
+ Rectangle {
+ anchors.fill: parent
+ color: JamiTheme.transparentColor
+ z: -1
+ }
+
+ property list menuTypoActionsSecond: [
+ Action {
+ id: quoteAction
+ property var iconSrc: JamiResources.quote_black_24dp_svg
+ property var shortcutText: JamiStrings.quote
+ property string shortcutKey: "Shift+Alt+9"
+ onTriggered: function clickAction() {
+ listViewTypo.addPrefixStyle(root.text, textArea.selectionStart, textArea.selectionEnd, "> ", false);
+ }
+ },
+ Action {
+ id: unorderedListAction
+ property var iconSrc: JamiResources.bullet_point_black_24dp_svg
+ property var shortcutText: JamiStrings.unorderedList
+ property string shortcutKey: "Shift+Alt+8"
+ onTriggered: function clickAction() {
+ listViewTypo.addPrefixStyle(root.text, textArea.selectionStart, textArea.selectionEnd, "- ", false);
+ }
+ },
+ Action {
+ id: orderedListAction
+ property var iconSrc: JamiResources.bullet_number_black_24dp_svg
+ property var shortcutText: JamiStrings.orderedList
+ property string shortcutKey: "Shift+Alt+7"
+ onTriggered: function clickAction() {
+ listViewTypo.addPrefixStyle(root.text, textArea.selectionStart, textArea.selectionEnd, "", true);
+ }
+ },
+ Action {
+ id: shiftEnterActiom
+ property var iconSrc: JamiResources.shift_enter_black_24dp_svg
+ property var shortcutText: chatViewEnterIsNewLine ? JamiStrings.enterNewLine : JamiStrings.shiftEnterNewLine
+ property var imageColor: chatViewEnterIsNewLine ? JamiTheme.chatViewFooterImgHoverColor : "#7f7f7f"
+ property var normalColor: chatViewEnterIsNewLine ? JamiTheme.hoveredButtonColor : JamiTheme.transparentColor
+ property var hasShortcut: false
+ property var shortcutKey: null
+ onTriggered: function clickAction() {
+ root.chatViewEnterIsNewLine = !root.chatViewEnterIsNewLine;
+ UtilsAdapter.setAppValue(Settings.Key.ChatViewEnterIsNewLine, chatViewEnterIsNewLine);
+ }
+ }
+ ]
+
+ model: menuTypoActionsSecond
+
+ delegate: PushButton {
+ anchors.verticalCenter: parent.verticalCenter
+
+ preferredSize: JamiTheme.chatViewFooterRealButtonSize
+ imageContainerWidth: 20
+ imageContainerHeight: 20
+ radius: 5
+
+ hoverEnabled: !showPreview
+ enabled: !showPreview
+
+ toolTipText: modelData.shortcutText
+ shortcutKey: modelData.shortcutKey
+ hasShortcut: modelData.hasShortcut != null ? modelData.hasShortcut : true
+ source: modelData.iconSrc
+ focusPolicy: Qt.TabFocus
+
+ normalColor: showPreview ? JamiTheme.transparentColor : (modelData.normalColor != null ? modelData.normalColor : JamiTheme.transparentColor)
+ imageColor: showPreview ? JamiTheme.chatViewFooterImgDisableColor : (hovered ? JamiTheme.chatViewFooterImgHoverColor : (modelData.imageColor != null ? modelData.imageColor : JamiTheme.chatViewFooterImgColor))
+ hoveredColor: JamiTheme.hoveredButtonColor
+ pressedColor: hoveredColor
+
+ action: modelData
}
}
}
- model: SortFilterProxyModel {
- sourceModel: listActions
- filters: [
- ExpressionFilter {
- expression: menuAction.show === true
- enabled: root.showDefault
- },
- ExpressionFilter {
- expression: menuAction.needWebEngine === false
- enabled: !WITH_WEBENGINE
- },
- ExpressionFilter {
- expression: menuAction.noSip === true
- enabled: CurrentConversation.isSip
- },
- ExpressionFilter {
- expression: menuAction.needVideoDevice === false
- enabled: VideoDevices.listSize === 0
- }
- ]
- }
-
- delegate: PushButton {
- id: buttonDelegate
- anchors.verticalCenter: parent ? parent.verticalCenter : undefined
- preferredSize: JamiTheme.chatViewFooterRealButtonSize
- imageContainerWidth: 20
- imageContainerHeight: 20
- radius: 5
-
- toolTipText: modelData.toolTip
- source: modelData.iconSrc
-
- normalColor: JamiTheme.chatViewFooterListColor
- imageColor: JamiTheme.chatViewFooterImgColor
- hoveredColor: JamiTheme.showMoreButtonOpenColor
- pressedColor: hoveredColor
-
- action: modelData
- }
- }
-
- Rectangle {
- z: -1
- radius: 0
- color: showMoreButton.normalColor
- width: JamiTheme.chatViewFooterButtonSize / 2
- height: JamiTheme.chatViewFooterButtonSize
-
PushButton {
- id: showMoreButton
- anchors.left: parent.left
+ id: typoButton
preferredSize: JamiTheme.chatViewFooterButtonSize
- imageContainerWidth: 20
- imageContainerHeight: 20
+ imageContainerWidth: 24
+ imageContainerHeight: 24
radius: JamiTheme.chatViewFooterButtonRadius
- toolTipText: showDefault ? JamiStrings.showMore : JamiStrings.showLess
+ hoverEnabled: !showPreview
+ enabled: !showPreview
- source: JamiResources.more_vert_24dp_svg
+ toolTipText: showTypo ? JamiStrings.hideFormating : JamiStrings.showFormating
+ source: JamiResources.text_edit_black_24dp_svg
- normalColor: showDefault ? JamiTheme.chatViewFooterListColor : JamiTheme.showMoreButtonOpenColor
- imageColor: JamiTheme.chatViewFooterImgColor
- pressedColor: JamiTheme.showMoreButtonOpenColor
- hoveredColor: JamiTheme.showMoreButtonOpenColor
+ normalColor: showPreview ? JamiTheme.transparentColor : (showTypo ? JamiTheme.hoveredButtonColor : JamiTheme.transparentColor)
+ imageColor: showPreview ? JamiTheme.chatViewFooterImgDisableColor : (hovered || showTypo ? JamiTheme.chatViewFooterImgHoverColor : JamiTheme.chatViewFooterImgColor)
+ hoveredColor: JamiTheme.hoveredButtonColor
+ pressedColor: hoveredColor
onClicked: {
- showDefault = !showDefault;
- if (showTypo)
- showTypo = false;
+ showTypo = !showTypo;
+ if (messageBar.width < messageBarLayoutMaximumWidth + sendButtonRow.width + 2 * JamiTheme.preferredMarginSize)
+ showTypoSecond = false;
+ if (!showDefault)
+ showDefault = true;
+ if (showTypo) {
+ root.chatViewEnterIsNewLine = true;
+ UtilsAdapter.setAppValue(Settings.Key.ChatViewEnterIsNewLine, true);
+ } else {
+ root.chatViewEnterIsNewLine = false;
+ UtilsAdapter.setAppValue(Settings.Key.ChatViewEnterIsNewLine, false);
+ }
UtilsAdapter.setAppValue(Settings.Key.ShowMardownOption, showTypo);
UtilsAdapter.setAppValue(Settings.Key.ShowSendOption, !showDefault);
}
}
}
- }
- }
- Row {
- id: sendButtonRow
- spacing: JamiTheme.chatViewFooterRowSpacing
- anchors.right: parent.right
- anchors.rightMargin: sendMessageButton.visible ? marginSize : 0
+ Row {
- PushButton {
- id: sendMessageButton
+ anchors.bottom: parent.bottom
+ anchors.bottomMargin: marginSize / 2
- objectName: "sendMessageButton"
+ ListView {
+ id: listViewAction
- width: scale * JamiTheme.chatViewFooterButtonSize
- height: JamiTheme.chatViewFooterButtonSize
+ width: contentWidth + 2 * leftMargin
- radius: JamiTheme.chatViewFooterButtonRadius
- preferredSize: JamiTheme.chatViewFooterButtonIconSize - 6
- imageContainerWidth: 25
- imageContainerHeight: 25
+ Behavior on width {
+ NumberAnimation {
+ duration: JamiTheme.longFadeDuration / 2
+ }
+ }
- toolTipText: JamiStrings.send
+ height: JamiTheme.chatViewFooterButtonSize
+ orientation: ListView.Horizontal
+ interactive: false
- mirror: UtilsAdapter.isRTL
+ leftMargin: 5
+ rightMargin: 5
+ spacing: 5
- source: JamiResources.send_black_24dp_svg
+ property list menuActions: [
+ Action {
+ id: sendFile
+ property var iconSrc: JamiResources.link_black_24dp_svg
+ property var toolTip: JamiStrings.sendFile
+ property bool show: true
+ property bool needWebEngine: false
+ property bool needVideoDevice: false
+ property bool noSip: false
+ onTriggered: function clickAction() {
+ sendFileButtonClicked();
+ }
+ },
+ Action {
+ id: addEmoji
+ property var iconSrc: JamiResources.emoji_black_24dp_svg
+ property var toolTip: JamiStrings.addEmoji
+ property bool show: true
+ property bool needWebEngine: true
+ property bool needVideoDevice: false
+ property bool noSip: true
+ onTriggered: function clickAction() {
+ emojiButtonClicked();
+ }
+ }
+ ]
- normalColor: JamiTheme.chatViewFooterSendButtonColor
- imageColor: JamiTheme.chatViewFooterSendButtonImgColor
- hoveredColor: JamiTheme.buttonTintedBlueHovered
- pressedColor: hoveredColor
+ ListModel {
+ id: listActions
+ Component.onCompleted: {
+ for (var i = 0; i < listViewAction.menuActions.length; i++) {
+ append({
+ "menuAction": listViewAction.menuActions[i]
+ });
+ }
+ }
+ }
- opacity: sendButtonVisibility ? 1 : 0
- visible: opacity
- scale: opacity
+ model: SortFilterProxyModel {
+ sourceModel: listActions
+ filters: [
+ ExpressionFilter {
+ expression: menuAction.show === true
+ enabled: root.showDefault
+ },
+ ExpressionFilter {
+ expression: menuAction.needWebEngine === false
+ enabled: !WITH_WEBENGINE
+ },
+ ExpressionFilter {
+ expression: menuAction.noSip === true
+ enabled: CurrentConversation.isSip
+ },
+ ExpressionFilter {
+ expression: menuAction.needVideoDevice === false
+ enabled: VideoDevices.listSize === 0
+ }
+ ]
+ }
- Behavior on opacity {
- enabled: animate
- NumberAnimation {
- duration: JamiTheme.shortFadeDuration
- easing.type: Easing.InOutQuad
+ delegate: PushButton {
+ id: buttonDelegate
+ anchors.verticalCenter: parent ? parent.verticalCenter : undefined
+ preferredSize: JamiTheme.chatViewFooterButtonSize
+ imageContainerWidth: 25
+ imageContainerHeight: 25
+ radius: 5
+
+ hoverEnabled: !showPreview
+ enabled: !showPreview
+
+ toolTipText: modelData.toolTip
+ source: modelData.iconSrc
+
+ normalColor: JamiTheme.transparentColor
+ imageColor: showPreview ? JamiTheme.chatViewFooterImgDisableColor : (hovered ? JamiTheme.chatViewFooterImgHoverColor : JamiTheme.chatViewFooterImgColor)
+ hoveredColor: JamiTheme.hoveredButtonColor
+ pressedColor: hoveredColor
+
+ action: modelData
+ }
+ }
+
+ ListView {
+ id: listViewMoreButton
+
+ width: 0
+ Behavior on width {
+ NumberAnimation {
+ duration: JamiTheme.longFadeDuration / 2
+ }
+ }
+
+ height: JamiTheme.chatViewFooterButtonSize
+ orientation: ListView.Horizontal
+ interactive: false
+
+ leftMargin: 10
+ rightMargin: 10
+ spacing: 10
+
+ property list menuMoreButton: [
+ Action {
+ id: leaveAudioMessage
+ property var iconSrc: JamiResources.message_audio_black_24dp_svg
+ property var toolTip: JamiStrings.leaveAudioMessage
+ property bool show: false
+ property bool needWebEngine: false
+ property bool needVideoDevice: false
+ property bool noSip: false
+ onTriggered: function clickAction() {
+ audioRecordMessageButtonClicked();
+ }
+ },
+ Action {
+ id: leaveVideoMessage
+ property var iconSrc: JamiResources.message_video_black_24dp_svg
+ property var toolTip: JamiStrings.leaveVideoMessage
+ property bool show: false
+ property bool needWebEngine: false
+ property bool needVideoDevice: true
+ property bool noSip: false
+ onTriggered: function clickAction() {
+ videoRecordMessageButtonClicked();
+ }
+ },
+ Action {
+ id: shareLocation
+ property var iconSrc: JamiResources.localisation_sharing_send_pin_svg
+ property var toolTip: JamiStrings.shareLocation
+ property bool show: false
+ property bool needWebEngine: true
+ property bool needVideoDevice: false
+ property bool noSip: false
+ onTriggered: function clickAction() {
+ showMapClicked();
+ }
+ }
+ ]
+
+ ListModel {
+ id: listMoreButton
+ Component.onCompleted: {
+ for (var i = 0; i < listViewMoreButton.menuMoreButton.length; i++) {
+ append({
+ "menuAction": listViewMoreButton.menuMoreButton[i]
+ });
+ }
+ }
+ }
+
+ model: SortFilterProxyModel {
+ sourceModel: listMoreButton
+ filters: [
+ ExpressionFilter {
+ expression: menuAction.show === true
+ enabled: showDefault
+ },
+ ExpressionFilter {
+ expression: menuAction.needWebEngine === false
+ enabled: !WITH_WEBENGINE
+ },
+ ExpressionFilter {
+ expression: menuAction.noSip === true
+ enabled: CurrentConversation.isSip
+ },
+ ExpressionFilter {
+ expression: menuAction.needVideoDevice === false
+ enabled: VideoDevices.listSize === 0
+ }
+ ]
+ }
+
+ delegate: PushButton {
+ id: buttonDelegateMoreButton
+ anchors.verticalCenter: parent ? parent.verticalCenter : undefined
+ preferredSize: JamiTheme.chatViewFooterRealButtonSize
+ imageContainerWidth: 20
+ imageContainerHeight: 20
+ radius: 5
+
+ toolTipText: modelData.toolTip
+ source: modelData.iconSrc
+
+ normalColor: JamiTheme.chatViewFooterListColor
+ imageColor: JamiTheme.chatViewFooterImgHoverColor
+ hoveredColor: JamiTheme.hoveredButtonColor
+ pressedColor: hoveredColor
+
+ action: modelData
+ }
}
}
+ }
- onClicked: root.sendMessageButtonClicked()
+ Rectangle {
+ color: JamiTheme.transparentColor
+ visible: false //showTypo
+ height: 50
+ width: previewButton.width + marginSize
+ Layout.row: showTypo ? 0 : 0
+ Layout.column: showTypo ? 1 : 1
+
+ PushButton {
+ id: previewButton
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.right: parent.right
+ anchors.rightMargin: marginSize
+ preferredSize: JamiTheme.chatViewFooterButtonSize
+ imageContainerWidth: 25
+ imageContainerHeight: 25
+ radius: 5
+ source: JamiResources.preview_black_24dp_svg
+ normalColor: showPreview ? hoveredColor : JamiTheme.transparentColor
+ imageColor: (hovered || showPreview) ? JamiTheme.chatViewFooterImgHoverColor : JamiTheme.chatViewFooterImgColor
+ hoveredColor: JamiTheme.hoveredButtonColor
+ pressedColor: hoveredColor
+
+ onClicked: {
+ showPreview = !showPreview;
+ }
+ }
}
}
}
+
+ Row {
+ id: sendButtonRow
+
+ spacing: JamiTheme.chatViewFooterRowSpacing
+
+ anchors.bottom: parent.bottom
+ anchors.right: parent.right
+ anchors.rightMargin: sendMessageButton.visible ? marginSize : 0
+ anchors.bottomMargin: marginSize / 2
+
+ PushButton {
+ id: sendMessageButton
+
+ objectName: "sendMessageButton"
+
+ width: scale * JamiTheme.chatViewFooterButtonSize
+ height: JamiTheme.chatViewFooterButtonSize
+
+ radius: JamiTheme.chatViewFooterButtonRadius
+ preferredSize: JamiTheme.chatViewFooterButtonIconSize - 6
+ imageContainerWidth: 25
+ imageContainerHeight: 25
+
+ toolTipText: JamiStrings.send
+
+ mirror: UtilsAdapter.isRTL
+
+ source: JamiResources.send_black_24dp_svg
+
+ normalColor: JamiTheme.chatViewFooterSendButtonColor
+ imageColor: JamiTheme.chatViewFooterSendButtonImgColor
+ hoveredColor: JamiTheme.buttonTintedBlueHovered
+ pressedColor: hoveredColor
+
+ opacity: sendButtonVisibility ? 1 : 0
+ visible: opacity
+ scale: opacity
+
+ Behavior on opacity {
+ enabled: animate
+ NumberAnimation {
+ duration: JamiTheme.shortFadeDuration
+ easing.type: Easing.InOutQuad
+ }
+ }
+
+ onClicked: sendMessageButtonClicked()
+ }
+ }
}
diff --git a/src/app/mainview/components/MessageBarTextArea.qml b/src/app/mainview/components/MessageBarTextArea.qml
index 75702f96..46e290f8 100644
--- a/src/app/mainview/components/MessageBarTextArea.qml
+++ b/src/app/mainview/components/MessageBarTextArea.qml
@@ -19,11 +19,17 @@ import QtQuick
import QtQuick.Controls
import net.jami.Adapters 1.1
import net.jami.Constants 1.1
+import net.jami.Enums 1.1
+import net.jami.Models 1.1
import "../../commoncomponents"
JamiFlickable {
id: root
+ property int maxWidth: 330
+ property bool tooMuch: {
+ return textArea.contentWidth > maxWidth;
+ }
property alias text: textArea.text
property var textAreaObj: textArea
property alias placeholderText: textArea.placeholderText
@@ -86,7 +92,7 @@ JamiFlickable {
wrapMode: TextEdit.Wrap
selectByMouse: true
textFormat: TextEdit.PlainText
- placeholderTextColor: JamiTheme.placeholderTextColor
+ placeholderTextColor: JamiTheme.messageBarPlaceholderTextColor
horizontalAlignment: Text.AlignLeft
background: Rectangle {
@@ -121,7 +127,9 @@ JamiFlickable {
MessagesAdapter.editId = CurrentConversation.lastSelfMessageId;
keyEvent.accepted = true;
} else if (keyEvent.key === Qt.Key_Enter || keyEvent.key === Qt.Key_Return) {
- if (!(keyEvent.modifiers & Qt.ShiftModifier)) {
+ const isEnterNewLine = UtilsAdapter.getAppValue(Settings.Key.ChatViewEnterIsNewLine);
+ const isShiftPressed = (keyEvent.modifiers & Qt.ShiftModifier);
+ if ((isEnterNewLine && isShiftPressed) || (!isEnterNewLine && !isShiftPressed)) {
root.sendMessagesRequired();
keyEvent.accepted = true;
}
diff --git a/src/app/mainview/components/MessageListView.qml b/src/app/mainview/components/MessageListView.qml
index 8da11323..442685cd 100644
--- a/src/app/mainview/components/MessageListView.qml
+++ b/src/app/mainview/components/MessageListView.qml
@@ -54,6 +54,10 @@ JamiListView {
return false
}
+ function scrollToBottom() {
+ verticalScrollBar.position = 1 - verticalScrollBar.size;
+ }
+
function computeChatview(item, itemIndex) {
if (!root) return
var rootItem = root.itemAtIndex(0)
@@ -277,7 +281,7 @@ JamiListView {
anchors.horizontalCenter: root.horizontalCenter
visible: 1 - verticalScrollBar.position >= verticalScrollBar.size * 2
- onClicked: verticalScrollBar.position = 1 - verticalScrollBar.size
+ onClicked: scrollToBottom()
}
header: Control {
diff --git a/src/app/mainview/components/Searchbar.qml b/src/app/mainview/components/Searchbar.qml
index 7f575a33..5f68fad6 100644
--- a/src/app/mainview/components/Searchbar.qml
+++ b/src/app/mainview/components/Searchbar.qml
@@ -76,7 +76,17 @@ Rectangle {
hoveredColor: JamiTheme.hoveredButtonColor
source: JamiResources.ic_baseline_search_24dp_svg
normalColor: "transparent"
- imageColor: JamiTheme.chatviewButtonColor
+ imageColor: {
+ if (reductionEnabled) {
+ if (hovered) {
+ JamiTheme.chatviewButtonColor;
+ } else {
+ JamiTheme.chatViewFooterImgColor;
+ }
+ } else {
+ JamiTheme.chatviewButtonColor;
+ }
+ }
onClicked: root.searchClicked()
}
@@ -99,7 +109,7 @@ Rectangle {
}
width: isOpen ? JamiTheme.searchbarSize : 0
- Behavior on width {
+ Behavior on width {
NumberAnimation {
duration: 150
}
diff --git a/src/app/messagesadapter.h b/src/app/messagesadapter.h
index 4a1fc7e1..a70c66d6 100644
--- a/src/app/messagesadapter.h
+++ b/src/app/messagesadapter.h
@@ -78,6 +78,7 @@ Q_SIGNALS:
void moreMessagesLoaded(qint32 loadingRequestId);
void timestampUpdated();
void fileCopied(const QString& dest);
+ void messageParsed(const QString& msgId, const QString& msg);
protected:
Q_INVOKABLE bool isDocument(const interaction::Type& type);