From c43978cb12e4335d9e3eed8a192860170b901609 Mon Sep 17 00:00:00 2001 From: Franck LAURENT <franck.laurent@savoirfairelinux.com> Date: Wed, 12 Apr 2023 17:20:16 -0400 Subject: [PATCH] ChatViewFooter: apply the new design GitLab: #1067 Change-Id: Ia80f85c678cb202d8e91cb3efe83d9ea82c40ae6 --- resources/icons/Bold_Black_24dp.svg | 16 + resources/icons/Bullet-number_Black_24dp.svg | 19 + resources/icons/Bullet-point_Black_24dp.svg | 18 + resources/icons/Code_Black_24dp.svg | 9 + resources/icons/Italic_Black_24dp.svg | 11 + resources/icons/Link_Web_Black_24dp.svg | 13 + resources/icons/Quote_Black_24dp.svg | 13 + resources/icons/S-Barre_Black_24dp.svg | 16 + resources/icons/Text-Edit_Black_24dp.svg | 26 + resources/icons/Title_Black_24dp.svg | 11 + src/app/appsettingsmanager.h | 4 +- src/app/commoncomponents/MarkdownPopup.qml | 95 ++ src/app/commoncomponents/PushButton.qml | 4 +- src/app/constant/JamiStrings.qml | 15 + src/app/constant/JamiTheme.qml | 11 +- src/app/mainview/MainView.qml | 10 +- .../mainview/components/ChatViewFooter.qml | 42 +- .../components/KeyboardShortcutTable.qml | 2 +- src/app/mainview/components/MessageBar.qml | 882 +++++++++++++++--- .../components/MessageBarTextArea.qml | 9 + src/app/settingsview/SettingsSidePanel.qml | 3 +- 21 files changed, 1054 insertions(+), 175 deletions(-) create mode 100644 resources/icons/Bold_Black_24dp.svg create mode 100644 resources/icons/Bullet-number_Black_24dp.svg create mode 100644 resources/icons/Bullet-point_Black_24dp.svg create mode 100644 resources/icons/Code_Black_24dp.svg create mode 100644 resources/icons/Italic_Black_24dp.svg create mode 100644 resources/icons/Link_Web_Black_24dp.svg create mode 100644 resources/icons/Quote_Black_24dp.svg create mode 100644 resources/icons/S-Barre_Black_24dp.svg create mode 100644 resources/icons/Text-Edit_Black_24dp.svg create mode 100644 resources/icons/Title_Black_24dp.svg create mode 100644 src/app/commoncomponents/MarkdownPopup.qml diff --git a/resources/icons/Bold_Black_24dp.svg b/resources/icons/Bold_Black_24dp.svg new file mode 100644 index 000000000..aa39b7d27 --- /dev/null +++ b/resources/icons/Bold_Black_24dp.svg @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Generator: Adobe Illustrator 24.3.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> +<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" + viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve"> +<style type="text/css"> + .st0{fill:#030504;} +</style> +<g id="Bold" transform="translate(-456.251 -437.592)"> + <path id="Path_265" class="st0" d="M467,459.6c-1.1,0-2.1,0-3.2-0.1c-1.1-0.1-2.2-0.2-3.3-0.5v-18.9c1-0.2,2-0.3,3-0.4 + c1.1-0.1,2.1-0.1,3-0.1c1.1,0,2.3,0.1,3.4,0.3c0.9,0.1,1.9,0.5,2.7,0.9c0.7,0.4,1.3,1,1.8,1.7c0.4,0.8,0.7,1.7,0.6,2.6 + c0,1.6-0.9,3-2.3,3.7c1,0.3,1.9,1,2.5,1.9c0.5,0.8,0.7,1.8,0.7,2.7c0.1,1.8-0.7,3.6-2.2,4.6C471.7,459.2,469.4,459.7,467,459.6z + M464.8,447.5h2.1c1,0.1,2-0.1,2.9-0.5c0.6-0.3,0.9-1,0.9-1.7c0.1-0.7-0.3-1.3-0.9-1.7c-0.8-0.4-1.7-0.5-2.6-0.5 + c-0.4,0-0.8,0-1.2,0c-0.4,0-0.8,0-1.2,0.1L464.8,447.5z M464.8,450.8v5c0.3,0,0.7,0.1,1,0.1c0.4,0,0.8,0,1.2,0 + c1.1,0,2.2-0.1,3.2-0.6c0.8-0.4,1.3-1.2,1.2-2.1c0.1-0.8-0.3-1.5-1-1.9c-0.9-0.4-1.9-0.6-2.9-0.6L464.8,450.8z"/> +</g> +</svg> diff --git a/resources/icons/Bullet-number_Black_24dp.svg b/resources/icons/Bullet-number_Black_24dp.svg new file mode 100644 index 000000000..e9405da58 --- /dev/null +++ b/resources/icons/Bullet-number_Black_24dp.svg @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Generator: Adobe Illustrator 24.3.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> +<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" + viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve"> +<style type="text/css"> + .st0{font-family:'Ubuntu-Bold';} + .st1{font-size:5.8624px;} +</style> +<g> + <g> + <path d="M8.2,6.8H21c0.6,0,1-0.5,1-1s-0.5-1-1-1H8.2c-0.6,0-1,0.5-1,1S7.6,6.8,8.2,6.8z"/> + <path d="M21,10.8H8.2c-0.6,0-1,0.5-1,1c0,0.6,0.5,1,1,1H21c0.6,0,1-0.5,1-1C22,11.2,21.5,10.8,21,10.8z"/> + <path d="M21,16.8H8.2c-0.6,0-1,0.5-1,1c0,0.6,0.5,1,1,1H21c0.6,0,1-0.5,1-1C22,17.3,21.5,16.8,21,16.8z"/> + </g> + <text transform="matrix(1 0 0 1 2.0002 7.9709)" class="st0 st1">1</text> + <text transform="matrix(1 0 0 1 2.0002 13.8333)" class="st0 st1">2</text> + <text transform="matrix(1 0 0 1 2.0002 19.6956)" class="st0 st1">3</text> +</g> +</svg> diff --git a/resources/icons/Bullet-point_Black_24dp.svg b/resources/icons/Bullet-point_Black_24dp.svg new file mode 100644 index 000000000..fdf546c0d --- /dev/null +++ b/resources/icons/Bullet-point_Black_24dp.svg @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Generator: Adobe Illustrator 24.3.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> +<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" + viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve"> +<g> + <path id="Path_247" d="M4,4.1c-1.2,0-2.1,1-2.1,2.1c0,1.2,1,2.1,2.1,2.1c1.2,0,2.1-1,2.1-2.1c0-0.6-0.2-1.1-0.6-1.5 + C5.1,4.4,4.6,4.1,4,4.1z"/> + <path id="Path_248" d="M4,9.9c-1.2,0-2.1,1-2.1,2.1c0,1.2,1,2.1,2.1,2.1c1.2,0,2.1-1,2.1-2.1c0-0.6-0.2-1.1-0.6-1.5 + C5.1,10.1,4.6,9.9,4,9.9z"/> + <path id="Path_249" d="M4,15.6c-1.2,0-2.1,1-2.1,2.1c0,1.2,1,2.1,2.1,2.1c1.2,0,2.1-1,2.1-2.1c0-0.6-0.2-1.1-0.6-1.5 + C5.1,15.8,4.6,15.6,4,15.6z"/> + <g> + <path d="M9,7.3h12.1c0.5,0,1-0.4,1-1s-0.4-1-1-1H9c-0.5,0-1,0.4-1,1S8.5,7.3,9,7.3z"/> + <path d="M21.2,11H9c-0.5,0-1,0.4-1,1s0.4,1,1,1h12.1c0.5,0,1-0.4,1-1S21.7,11,21.2,11z"/> + <path d="M21.2,16.8H9c-0.5,0-1,0.4-1,1c0,0.5,0.4,1,1,1h12.1c0.5,0,1-0.4,1-1C22.1,17.2,21.7,16.8,21.2,16.8z"/> + </g> +</g> +</svg> diff --git a/resources/icons/Code_Black_24dp.svg b/resources/icons/Code_Black_24dp.svg new file mode 100644 index 000000000..1b94d1027 --- /dev/null +++ b/resources/icons/Code_Black_24dp.svg @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Generator: Adobe Illustrator 24.3.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> +<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" + viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve"> +<path id="Code" d="M7.7,5.9C7.5,5.9,7.3,6,7.1,6.2l-4.8,5.2l0,0c-0.3,0.4-0.3,0.9,0,1.2l4.8,5.2c0.3,0.4,0.9,0.5,1.3,0.2 + c0.4-0.3,0.5-0.9,0.2-1.3c0,0-0.1-0.1-0.1-0.1L4.2,12l4.3-4.5c0.3-0.4,0.3-0.9,0-1.3C8.2,6,8,5.9,7.7,5.9z M16.2,5.9L16.2,5.9 + c-0.5,0-0.9,0.5-0.8,1c0,0.2,0.1,0.4,0.2,0.5l4.3,4.5l-4.3,4.5c-0.4,0.3-0.4,0.9-0.1,1.3c0.3,0.4,0.9,0.4,1.3,0.1 + c0,0,0.1-0.1,0.1-0.1l4.8-5.2c0.3-0.4,0.3-0.9,0-1.2l-4.8-5.2C16.7,6,16.4,5.9,16.2,5.9L16.2,5.9z"/> +</svg> diff --git a/resources/icons/Italic_Black_24dp.svg b/resources/icons/Italic_Black_24dp.svg new file mode 100644 index 000000000..30f2b0176 --- /dev/null +++ b/resources/icons/Italic_Black_24dp.svg @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Generator: Adobe Illustrator 24.3.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> +<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" + viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve"> +<style type="text/css"> + .st0{fill:#030504;} +</style> +<g id="Italic" transform="translate(-500.334 -437.712)"> + <path id="Path_266" class="st0" d="M513.3,439.7h2.8l-4.8,20h-2.8L513.3,439.7z"/> +</g> +</svg> diff --git a/resources/icons/Link_Web_Black_24dp.svg b/resources/icons/Link_Web_Black_24dp.svg new file mode 100644 index 000000000..114bb5fa0 --- /dev/null +++ b/resources/icons/Link_Web_Black_24dp.svg @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Generator: Adobe Illustrator 24.3.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> +<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" + viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve"> +<g id="Link"> + <path d="M10.9,8.7c-1.2,0-2.3,0.5-3.1,1.3l-4.6,4.6C2.5,15.4,2,16.5,2,17.6c0,1.2,0.5,2.3,1.3,3.1S5.2,22,6.3,22s2.3-0.5,3.1-1.3 + l3.3-3.3c-0.7,0-1.3-0.2-1.9-0.4l-2.6,2.6c-1.1,1.1-2.8,1.1-3.8,0l-0.1-0.1l0,0c-0.4-0.5-0.7-1.1-0.7-1.8c0-0.7,0.3-1.4,0.8-1.9 + l0,0L9,11.1c1-1,2.8-1,3.8,0c0.3,0.3,0.9,0.3,1.2,0c0.2-0.2,0.2-0.4,0.2-0.6S14.2,10.1,14,10C13.2,9.2,12.1,8.7,10.9,8.7z + M10.6,12.6c-0.2,0-0.4,0.1-0.6,0.2c-0.3,0.3-0.3,0.9,0,1.2c1.7,1.7,4.5,1.7,6.1,0l4.6-4.6C21.5,8.6,22,7.5,22,6.4 + s-0.5-2.3-1.3-3.1c-1.7-1.7-4.5-1.7-6.1,0l-3.3,3.3c0.7,0,1.3,0.2,1.9,0.4l2.6-2.6c0.5-0.5,1.2-0.8,1.9-0.8c0.7,0,1.4,0.3,1.9,0.8 + c0.5,0.5,0.8,1.2,0.8,1.9s-0.3,1.4-0.8,1.9L15,12.9c-1,1-2.8,1.1-3.8,0C11,12.7,10.8,12.6,10.6,12.6z"/> +</g> +</svg> diff --git a/resources/icons/Quote_Black_24dp.svg b/resources/icons/Quote_Black_24dp.svg new file mode 100644 index 000000000..f91863fe7 --- /dev/null +++ b/resources/icons/Quote_Black_24dp.svg @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Generator: Adobe Illustrator 24.3.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> +<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" + viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve"> +<g id="Quote" transform="translate(-119.998 -268.136)"> + <path id="Path_245" d="M140.3,278.1h-3.3c-0.2-1.5,0.1-3,0.9-4.2c0.1-0.2,0.1-0.5-0.1-0.6c-0.1-0.1-0.3-0.1-0.4,0 + c-0.6,0.3-1.2,0.6-1.7,1.1c-1.4,1.4-2.3,3.2-2.4,5.1c0,0.2,0,0.3,0,0.4v5.5c0,1,0.8,1.7,1.7,1.7h5.5c1,0,1.7-0.8,1.8-1.7 + c0,0,0,0,0,0v-5.5C142,278.9,141.2,278.1,140.3,278.1z"/> + <path id="Path_246" d="M129.2,278.1h-3.3c-0.1-0.9-0.1-1.8,0.2-2.7c0.2-0.5,0.4-1.1,0.7-1.5c0.1-0.2,0.1-0.5-0.1-0.6 + c-0.1-0.1-0.3-0.1-0.4,0c-0.6,0.3-1.2,0.6-1.7,1.1c-1.4,1.4-2.3,3.2-2.4,5.1c0,0.2,0,0.3,0,0.4v5.5c0,1,0.8,1.7,1.7,1.8 + c0,0,0,0,0,0h5.5c1,0,1.7-0.8,1.8-1.7c0,0,0,0,0,0v-5.5C131,278.9,130.2,278.1,129.2,278.1L129.2,278.1z"/> +</g> +</svg> diff --git a/resources/icons/S-Barre_Black_24dp.svg b/resources/icons/S-Barre_Black_24dp.svg new file mode 100644 index 000000000..992e68ef5 --- /dev/null +++ b/resources/icons/S-Barre_Black_24dp.svg @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Generator: Adobe Illustrator 24.3.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> +<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" + viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve"> +<g id="Barre" transform="translate(-538.1 -437.472)"> + <path id="Path_267" d="M549.6,457.1c2.8,0,4.2-1,4.2-2.9c0-0.5-0.1-1-0.4-1.5c-0.3-0.4-0.6-0.8-1-1.1c-0.5-0.3-0.9-0.6-1.5-0.8 + c-0.5-0.2-1.1-0.4-1.7-0.7c-0.7-0.2-1.3-0.5-2-0.8c-0.6-0.3-1.1-0.6-1.6-1.1c-0.5-0.4-0.8-0.9-1.1-1.5c-0.3-0.7-0.4-1.4-0.4-2.1 + c-0.1-1.5,0.6-3,1.7-3.9c1.4-1,3-1.5,4.7-1.4c1.1,0,2.1,0.1,3.2,0.4c0.7,0.2,1.4,0.4,2.1,0.8l-0.9,2.2c-0.5-0.3-1.1-0.5-1.7-0.7 + c-0.9-0.2-1.8-0.4-2.7-0.3c-0.5,0-1,0.1-1.4,0.2c-0.4,0.1-0.8,0.3-1.2,0.5c-0.3,0.2-0.6,0.5-0.8,0.8c-0.2,0.4-0.3,0.8-0.3,1.2 + c0,0.5,0.1,0.9,0.3,1.3c0.2,0.4,0.5,0.7,0.9,0.9c0.4,0.3,0.8,0.5,1.3,0.7c0.5,0.2,1,0.4,1.6,0.7c0.8,0.3,1.6,0.7,2.3,1 + c0.7,0.3,1.3,0.7,1.8,1.2c0.5,0.5,0.9,1,1.2,1.6c0.3,0.7,0.4,1.5,0.4,2.3c0.1,1.5-0.6,3-1.8,3.9c-1.5,1-3.4,1.5-5.2,1.4 + c-0.7,0-1.4,0-2.1-0.2c-0.6-0.1-1.1-0.2-1.7-0.4c-0.4-0.1-0.9-0.3-1.3-0.4c-0.4-0.2-0.6-0.3-0.8-0.4l0.8-2.2 + c0.6,0.3,1.3,0.6,1.9,0.8C547.4,457,548.5,457.2,549.6,457.1z"/> + <path id="Path_268" d="M542.8,453v-2.2h14.7v2.2H542.8z"/> +</g> +</svg> diff --git a/resources/icons/Text-Edit_Black_24dp.svg b/resources/icons/Text-Edit_Black_24dp.svg new file mode 100644 index 000000000..87ba9cf6f --- /dev/null +++ b/resources/icons/Text-Edit_Black_24dp.svg @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Generator: Adobe Illustrator 24.3.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> +<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" + viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve"> +<g id="noun-text-edit-1483720" transform="translate(-240 -240)"> + <g id="Path_259"> + <path d="M252.6,242v3.6h-1.3v-1.8v-0.5h-0.5h-2.3H248v0.5v11.7v0.5h0.5h1.8v1.3h-6V256h1.8h0.5v-0.5v-11.7v-0.5h-0.5h-2.3h-0.5 + v0.5v1.8H242V242H252.6"/> + </g> + <g id="Path_260"> + <path d="M262,256v1.3h-6V256H262"/> + </g> + <g id="Path_261"> + <path d="M262,260.7v1.3h-20v-1.3H262"/> + </g> + <g id="Path_262"> + <path d="M257.3,251.4v1.3H256v-1.3H257.3"/> + </g> + <g id="Path_263"> + <path d="M262,246.7v1.3h-6v-1.3H262"/> + </g> + <g id="Path_264"> + <path d="M259.7,242v1.3H256V242H259.7"/> + </g> +</g> +</svg> diff --git a/resources/icons/Title_Black_24dp.svg b/resources/icons/Title_Black_24dp.svg new file mode 100644 index 000000000..e4a003ffa --- /dev/null +++ b/resources/icons/Title_Black_24dp.svg @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Generator: Adobe Illustrator 24.3.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> +<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" + viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve"> +<style type="text/css"> + .st0{fill:#030504;} +</style> +<g id="Title" transform="translate(-579.093 -437.712)"> + <path id="Path_269" class="st0" d="M596,439.7h2.8v20H596v-9.2h-9.8v9.2h-2.8v-20h2.8v8.3h9.8V439.7z"/> +</g> +</svg> diff --git a/src/app/appsettingsmanager.h b/src/app/appsettingsmanager.h index c81bf7630..8ba68379a 100644 --- a/src/app/appsettingsmanager.h +++ b/src/app/appsettingsmanager.h @@ -58,7 +58,9 @@ extern const QString defaultDownloadPath; X(LANG, "SYSTEM") \ X(PositionShareDuration, 15) \ X(PositionShareLimit, true) \ - X(FlipSelf, true) + X(FlipSelf, true) \ + X(ShowMardownOption, false) \ + X(ShowSendOption, false) /* * A class to expose settings keys in both c++ and QML. diff --git a/src/app/commoncomponents/MarkdownPopup.qml b/src/app/commoncomponents/MarkdownPopup.qml new file mode 100644 index 000000000..433226f52 --- /dev/null +++ b/src/app/commoncomponents/MarkdownPopup.qml @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2023 Savoir-faire Linux Inc. + * Author: Franck Laurent <nicolas.vengeon@savoirfairelinux.com> + * + * 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 <https://www.gnu.org/licenses/>. + */ +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<Action> menuTypoActionsSecond + + contentItem: ListView { + id: listViewTypoSecond + + width: contentWidth + leftMargin + height: JamiTheme.chatViewFooterButtonSize + orientation: ListView.Horizontal + interactive: false + leftMargin: 10 + spacing: 10 + + Rectangle { + anchors.fill: parent + color: JamiTheme.chatViewFooterListColor + radius: 5 + z: -1 + } + + model: menuTypoActionsSecond + + delegate: PushButton { + anchors.verticalCenter: parent.verticalCenter + + 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 + } + } + + background: Rectangle { + anchors.fill: parent + color: JamiTheme.chatViewFooterListColor + 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/commoncomponents/PushButton.qml b/src/app/commoncomponents/PushButton.qml index 951eacea8..6c6ee8ca9 100644 --- a/src/app/commoncomponents/PushButton.qml +++ b/src/app/commoncomponents/PushButton.qml @@ -169,7 +169,7 @@ AbstractButton { }, State { name: "hovered" - when: hovered || root.focus + when: hovered || root.activeFocus PropertyChanges { target: background color: hoveredColor @@ -177,7 +177,7 @@ AbstractButton { }, State { name: "forceHovered" - when: forceHovered || root.focus + when: forceHovered || root.activeFocus PropertyChanges { target: background color: hoveredColor diff --git a/src/app/constant/JamiStrings.qml b/src/app/constant/JamiStrings.qml index 6a6853a84..519475bf9 100644 --- a/src/app/constant/JamiStrings.qml +++ b/src/app/constant/JamiStrings.qml @@ -790,6 +790,21 @@ Item { property string sendFile: qsTr("Send file") property string leaveAudioMessage: qsTr("Leave audio message") property string leaveVideoMessage: qsTr("Leave video message") + property string showMore: qsTr("Show more") + property string showLess: qsTr("Show less") + + property string bold: qsTr("Bold") + property string italic: qsTr("Italic") + property string barre: qsTr("Barre") + property string title: qsTr("Title") + property string link: qsTr("Link") + property string code: qsTr("Code") + property string quote: qsTr("Quote") + property string bulletPoint: qsTr("Bullet Point") + property string bulletNumber: qsTr("Bullet Number") + property string showFormating: qsTr("Show Formating") + property string hideFormating: qsTr("Hide Formating") + 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 9c013eed3..999410c88 100644 --- a/src/app/constant/JamiTheme.qml +++ b/src/app/constant/JamiTheme.qml @@ -231,6 +231,14 @@ Item { property color messageWebViewFooterButtonImageColor: darkTheme ? "#838383" : "#656565" property color chatviewUsernameColor: "#A7A7A7" + //ChatView Footer + property color chatViewFooterListColor: darkTheme ? blackColor : "#E5E5E5" + property color chatViewFooterImgColor: darkTheme ? whiteColor : blackColor + property color showMoreButtonOpenColor: darkTheme ? "#123F4A" : "#CCCCCC" + property color chatViewFooterSeparateLineColor: darkTheme ? "#5c5c5c" : "#929292" + property color chatViewFooterSendButtonColor: darkTheme ? "#03B9E9" : "#005699" + property color chatViewFooterSendButtonImgColor: darkTheme ? blackColor : whiteColor + //mapPosition property color mapButtonsOverlayColor: darkTheme ? "#000000" : "#f0f0f0" property color mapButtonColor: darkTheme ? "#f0f0f0" : "#000000" @@ -429,8 +437,9 @@ Item { property real chatViewHeaderPreferredHeight: 64 property real chatViewFooterPreferredHeight: 50 property real chatViewFooterMaximumHeight: 280 - property real chatViewFooterRowSpacing: 1 + property real chatViewFooterRowSpacing: 4 property real chatViewFooterButtonSize: 36 + property real chatViewFooterRealButtonSize: 26 property real chatViewFooterButtonIconSize: 48 property real chatViewFooterButtonRadius: 5 property real chatViewFooterTextAreaMaximumHeight: 130 diff --git a/src/app/mainview/MainView.qml b/src/app/mainview/MainView.qml index 9f55a9723..6735e2b09 100644 --- a/src/app/mainview/MainView.qml +++ b/src/app/mainview/MainView.qml @@ -66,7 +66,7 @@ Rectangle { Shortcut { sequence: "Ctrl+M" context: Qt.ApplicationShortcut - onActivated: JamiQmlUtils.settingsPageRequested(SettingsView.Media) + onActivated: JamiQmlUtils.settingsPageRequested(12) } WheelHandler { @@ -119,19 +119,19 @@ Rectangle { Shortcut { sequence: "Ctrl+G" context: Qt.ApplicationShortcut - onActivated: JamiQmlUtils.settingsPageRequested(SettingsView.General) + onActivated: JamiQmlUtils.settingsPageRequested(5) } Shortcut { - sequence: "Ctrl+I" + sequence: "Ctrl+Alt+I" context: Qt.ApplicationShortcut - onActivated: JamiQmlUtils.settingsPageRequested(SettingsView.Account) + onActivated: JamiQmlUtils.settingsPageRequested(0) } Shortcut { sequence: "Ctrl+P" context: Qt.ApplicationShortcut - onActivated: JamiQmlUtils.settingsPageRequested(SettingsView.Plugin) + onActivated: JamiQmlUtils.settingsPageRequested(15) } Shortcut { diff --git a/src/app/mainview/components/ChatViewFooter.qml b/src/app/mainview/components/ChatViewFooter.qml index aa892727f..325e96515 100644 --- a/src/app/mainview/components/ChatViewFooter.qml +++ b/src/app/mainview/components/ChatViewFooter.qml @@ -130,7 +130,6 @@ Rectangle { Layout.alignment: Qt.AlignHCenter Layout.preferredWidth: footerColumnLayout.width - Layout.preferredHeight: implicitHeight property var emojiPicker Connections { @@ -157,17 +156,16 @@ Rectangle { } function setXposition() { - return messageBar.width - JamiTheme.emojiPickerWidth; //- JamiTheme.emojiMargins + return messageBar.width - JamiTheme.emojiPickerWidth; } function setYposition() { - return -JamiTheme.emojiPickerHeight; //- JamiTheme.emojiMargins + return -JamiTheme.emojiPickerHeight; } sendButtonVisibility: text || dataTransferSendContainer.filesToSendCount onEmojiButtonClicked: { - JamiQmlUtils.updateMessageBarButtonsPoints(); openEmojiPicker(); } @@ -185,6 +183,16 @@ Rectangle { }); } + onVideoRecordMessageButtonClicked: { + recordBox.y = -recordBox.height; + recordBox.openRecorder(true); + } + + onAudioRecordMessageButtonClicked: { + recordBox.y = -recordBox.height; + recordBox.openRecorder(false); + } + onSendMessageButtonClicked: { // Send file messages var fileCounts = dataTransferSendContainer.filesToSendListModel.rowCount(); @@ -205,32 +213,6 @@ Rectangle { messageBar.textAreaObj.clearText(); MessagesAdapter.replyToId = ""; } - onVideoRecordMessageButtonClicked: { - JamiQmlUtils.updateMessageBarButtonsPoints(); - recordBox.parent = JamiQmlUtils.mainViewRectObj; - recordBox.x = Qt.binding(function () { - var buttonCenterX = JamiQmlUtils.videoRecordMessageButtonInMainViewPoint.x + JamiQmlUtils.videoRecordMessageButtonObj.width / 2; - return buttonCenterX - recordBox.width / 2; - }); - recordBox.y = Qt.binding(function () { - var buttonY = JamiQmlUtils.videoRecordMessageButtonInMainViewPoint.y; - return buttonY - recordBox.height - recordBox.spikeHeight; - }); - recordBox.openRecorder(true); - } - onAudioRecordMessageButtonClicked: { - JamiQmlUtils.updateMessageBarButtonsPoints(); - recordBox.parent = JamiQmlUtils.mainViewRectObj; - recordBox.x = Qt.binding(function () { - var buttonCenterX = JamiQmlUtils.audioRecordMessageButtonInMainViewPoint.x + JamiQmlUtils.audioRecordMessageButtonObj.width / 2; - return buttonCenterX - recordBox.width / 2; - }); - recordBox.y = Qt.binding(function () { - var buttonY = JamiQmlUtils.audioRecordMessageButtonInMainViewPoint.y; - return buttonY - recordBox.height - recordBox.spikeHeight; - }); - recordBox.openRecorder(false); - } } FilesToSendContainer { diff --git a/src/app/mainview/components/KeyboardShortcutTable.qml b/src/app/mainview/components/KeyboardShortcutTable.qml index 39561e1e9..f1dac9d2d 100644 --- a/src/app/mainview/components/KeyboardShortcutTable.qml +++ b/src/app/mainview/components/KeyboardShortcutTable.qml @@ -151,7 +151,7 @@ Window { description: qsTr("General settings") } ListElement { - shortcut: "Ctrl + I" + shortcut: "Ctrl + Alt + I" shortcut2: "" description: qsTr("Account settings") } diff --git a/src/app/mainview/components/MessageBar.qml b/src/app/mainview/components/MessageBar.qml index f0bd91f53..55b398c4d 100644 --- a/src/app/mainview/components/MessageBar.qml +++ b/src/app/mainview/components/MessageBar.qml @@ -17,8 +17,11 @@ */ import QtQuick import QtQuick.Layouts +import QtQuick.Controls +import SortFilterProxyModel 0.2 import net.jami.Adapters 1.1 import net.jami.Models 1.1 +import net.jami.Enums 1.1 import net.jami.Constants 1.1 import "../../commoncomponents" @@ -30,6 +33,11 @@ ColumnLayout { property real marginSize: JamiTheme.messageBarMarginSize property bool sendButtonVisibility: false property bool animate: false + property bool showDefault: !UtilsAdapter.getAppValue(Settings.Key.ShowSendOption) + property bool showTypo: UtilsAdapter.getAppValue(Settings.Key.ShowMardownOption) + property bool showTypoSecond: false + + property int messageBarLayoutMaximumWidth: 486 signal sendMessageButtonClicked signal sendFileButtonClicked @@ -38,9 +46,7 @@ ColumnLayout { signal showMapClicked signal emojiButtonClicked - implicitHeight: messageBarRowLayout.height - - spacing: 0 + spacing: 5 Rectangle { id: messageBarHairLine @@ -52,188 +58,796 @@ ColumnLayout { color: JamiTheme.tabbarBorderColor } - RowLayout { - id: messageBarRowLayout - - Layout.alignment: Qt.AlignCenter - Layout.fillWidth: true - Layout.maximumWidth: JamiTheme.chatViewMaximumWidth - - spacing: JamiTheme.chatViewFooterRowSpacing - - PushButton { - id: showMapButton + MessageBarTextArea { + id: textArea - Layout.alignment: Qt.AlignVCenter - Layout.leftMargin: marginSize - Layout.preferredWidth: JamiTheme.chatViewFooterButtonSize - Layout.preferredHeight: JamiTheme.chatViewFooterButtonSize - visible: WITH_WEBENGINE && !CurrentConversation.isSip + objectName: "messageBarTextArea" - radius: JamiTheme.chatViewFooterButtonRadius - preferredSize: JamiTheme.chatViewFooterButtonIconSize - - toolTipText: JamiStrings.shareLocation - - source: JamiResources.share_location_svg - - normalColor: JamiTheme.primaryBackgroundColor - imageColor: JamiTheme.messageWebViewFooterButtonImageColor - - onClicked: root.showMapClicked() + // forward activeFocus to the actual text area object + onActiveFocusChanged: { + if (activeFocus) + textAreaObj.forceActiveFocus(); } - PushButton { - id: sendFileButton - - Layout.alignment: Qt.AlignVCenter - Layout.preferredWidth: JamiTheme.chatViewFooterButtonSize - Layout.preferredHeight: JamiTheme.chatViewFooterButtonSize + placeholderText: JamiStrings.writeTo.arg(CurrentConversation.title) - radius: JamiTheme.chatViewFooterButtonRadius - preferredSize: JamiTheme.chatViewFooterButtonIconSize - 6 - - toolTipText: JamiStrings.sendFile - visible: !CurrentConversation.isSip - - source: JamiResources.link_black_24dp_svg - - normalColor: JamiTheme.primaryBackgroundColor - imageColor: JamiTheme.messageWebViewFooterButtonImageColor + Layout.alignment: Qt.AlignVCenter + Layout.fillWidth: true + Layout.leftMargin: marginSize / 2 + Layout.rightMargin: marginSize / 2 + Layout.preferredHeight: { + return JamiTheme.chatViewFooterPreferredHeight > contentHeight ? JamiTheme.chatViewFooterPreferredHeight : contentHeight; + } + Layout.maximumHeight: JamiTheme.chatViewFooterTextAreaMaximumHeight - marginSize / 2 + + onSendMessagesRequired: root.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(); + }, + "Bulleted List": function () { + listViewTypoSecond.itemAtIndex(3).action.triggered(); + }, + "Numbered List": function () { + listViewTypoSecond.itemAtIndex(4).action.triggered(); + } + } - onClicked: root.sendFileButtonClicked() + Shortcut { + sequence: "Ctrl+B" + context: Qt.ApplicationShortcut + onActivated: textArea.markdownShortCut["Bold"]() } - PushButton { - id: audioRecordMessageButton + Shortcut { + sequence: "Ctrl+I" + context: Qt.ApplicationShortcut + onActivated: textArea.markdownShortCut["Italic"]() + } - Layout.alignment: Qt.AlignVCenter - Layout.preferredWidth: JamiTheme.chatViewFooterButtonSize - Layout.preferredHeight: JamiTheme.chatViewFooterButtonSize + Shortcut { + sequence: "Shift+Alt+X" + context: Qt.ApplicationShortcut + onActivated: textArea.markdownShortCut["Barre"]() + } - radius: JamiTheme.chatViewFooterButtonRadius - preferredSize: JamiTheme.chatViewFooterButtonIconSize + Shortcut { + sequence: "Ctrl+Alt+H" + context: Qt.ApplicationShortcut + onActivated: textArea.markdownShortCut["Heading"]() + } - toolTipText: JamiStrings.leaveAudioMessage - visible: !CurrentConversation.isSip + Shortcut { + sequence: "Ctrl+Alt+K" + context: Qt.ApplicationShortcut + onActivated: textArea.markdownShortCut["Link"]() + } - source: JamiResources.message_audio_black_24dp_svg + Shortcut { + sequence: "Ctrl+Alt+C" + context: Qt.ApplicationShortcut + onActivated: textArea.markdownShortCut["Code"]() + } - normalColor: JamiTheme.primaryBackgroundColor - imageColor: JamiTheme.messageWebViewFooterButtonImageColor + Shortcut { + sequence: "Shift+Alt+9" + context: Qt.ApplicationShortcut + onActivated: textArea.markdownShortCut["Quote"]() + } - onClicked: root.audioRecordMessageButtonClicked() + Shortcut { + sequence: "Shift+Alt+8" + context: Qt.ApplicationShortcut + onActivated: textArea.markdownShortCut["Bulleted List"]() + } - Component.onCompleted: JamiQmlUtils.audioRecordMessageButtonObj = audioRecordMessageButton + Shortcut { + sequence: "Shift+Alt+7" + context: Qt.ApplicationShortcut + onActivated: textArea.markdownShortCut["Numbered List"]() } + } - PushButton { - id: videoRecordMessageButton + Item { + id: messageBar + Layout.fillWidth: true + Layout.preferredHeight: JamiTheme.chatViewFooterButtonSize + Layout.leftMargin: marginSize + Layout.bottomMargin: marginSize + + onWidthChanged: { + if (width < messageBarRowLayout.width + sendButtonRow.width + 2 * JamiTheme.preferredMarginSize) { + showTypoSecond = false; + } else { + if (width > 2 * messageBarRowLayout.width) { + showTypoSecond = true; + } + } + } - Layout.alignment: Qt.AlignVCenter - Layout.preferredWidth: JamiTheme.chatViewFooterButtonSize - Layout.preferredHeight: JamiTheme.chatViewFooterButtonSize - visible: VideoDevices.listSize !== 0 && !CurrentConversation.isSip + RowLayout { + id: messageBarRowLayout - radius: JamiTheme.chatViewFooterButtonRadius - preferredSize: JamiTheme.chatViewFooterButtonIconSize + spacing: JamiTheme.chatViewFooterRowSpacing - toolTipText: JamiStrings.leaveVideoMessage + Row { - source: JamiResources.message_video_black_24dp_svg + PushButton { + id: typoButton - normalColor: JamiTheme.primaryBackgroundColor - imageColor: JamiTheme.messageWebViewFooterButtonImageColor + preferredSize: JamiTheme.chatViewFooterButtonSize + imageContainerWidth: 24 + imageContainerHeight: 24 - onClicked: root.videoRecordMessageButtonClicked() + radius: JamiTheme.chatViewFooterButtonRadius - Component.onCompleted: JamiQmlUtils.videoRecordMessageButtonObj = videoRecordMessageButton - } + toolTipText: showTypo ? JamiStrings.hideFormating : JamiStrings.showFormating + source: JamiResources.text_edit_black_24dp_svg - MessageBarTextArea { - id: textArea + normalColor: !showTypo ? JamiTheme.chatViewFooterListColor : JamiTheme.showMoreButtonOpenColor + imageColor: JamiTheme.chatViewFooterImgColor + pressedColor: JamiTheme.showMoreButtonOpenColor + hoveredColor: JamiTheme.showMoreButtonOpenColor - objectName: "messageBarTextArea" + 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); + } - // forward activeFocus to the actual text area object - onActiveFocusChanged: { - if (activeFocus) - textAreaObj.forceActiveFocus(); - } + Rectangle { + visible: showTypo - placeholderText: JamiStrings.writeTo.arg(CurrentConversation.title) + anchors.fill: parent + anchors.leftMargin: 3 + anchors.rightMargin: -5 + color: JamiTheme.showMoreButtonOpenColor + z: -2 + } + } - Layout.alignment: Qt.AlignVCenter - Layout.fillWidth: true - Layout.margins: marginSize / 2 - Layout.preferredHeight: { - return JamiTheme.chatViewFooterPreferredHeight > contentHeight ? JamiTheme.chatViewFooterPreferredHeight : contentHeight; + Row { + id: listViewTypo + height: JamiTheme.chatViewFooterButtonSize + + 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); + } + } + + function addPrefixStyle(message, selectionStart, selectionEnd, delimiter, isBulletNumber) { + + //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 (!isBulletNumber) { + 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 + } + } + + 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<Action> menuTypoActionsFirst: [ + Action { + id: boldAction + property var iconSrc: JamiResources.bold_black_24dp_svg + property var toolTip: JamiStrings.bold + + onTriggered: function clickAction() { + listViewTypo.addStyle(root.text, textArea.selectionStart, textArea.selectionEnd, "**", "**"); + } + }, + Action { + id: italicAction + property var iconSrc: JamiResources.italic_black_24dp_svg + property var toolTip: JamiStrings.italic + onTriggered: function clickAction() { + listViewTypo.addStyle(root.text, textArea.selectionStart, textArea.selectionEnd, "*", "*"); + } + }, + Action { + id: barreAction + property var iconSrc: JamiResources.s_barre_black_24dp_svg + property var toolTip: JamiStrings.barre + onTriggered: function clickAction() { + listViewTypo.addStyle(root.text, textArea.selectionStart, textArea.selectionEnd, "~~", "~~"); + } + }, + Action { + id: titleAction + property var iconSrc: JamiResources.title_black_24dp_svg + property var toolTip: JamiStrings.title + 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.toolTip + source: modelData.iconSrc + + 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 + } + } + + 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 + } + } + + 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<Action> menuTypoActionsSecond: [ + Action { + id: linkAction + property var iconSrc: JamiResources.link_web_black_24dp_svg + property var toolTip: JamiStrings.link + 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 toolTip: JamiStrings.code + onTriggered: function clickAction() { + listViewTypo.addStyle(root.text, textArea.selectionStart, textArea.selectionEnd, "```", "```"); + } + }, + Action { + id: quoteAction + property var iconSrc: JamiResources.quote_black_24dp_svg + property var toolTip: JamiStrings.quote + onTriggered: function clickAction() { + listViewTypo.addPrefixStyle(root.text, textArea.selectionStart, textArea.selectionEnd, "> ", false); + } + }, + Action { + id: bulletPointAction + property var iconSrc: JamiResources.bullet_point_black_24dp_svg + property var toolTip: JamiStrings.bulletPoint + onTriggered: function clickAction() { + listViewTypo.addPrefixStyle(root.text, textArea.selectionStart, textArea.selectionEnd, "- ", false); + } + }, + Action { + id: bulletNumberAction + property var iconSrc: JamiResources.bullet_number_black_24dp_svg + property var toolTip: JamiStrings.bulletNumber + 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.toolTip + source: modelData.iconSrc + + normalColor: JamiTheme.chatViewFooterListColor + imageColor: JamiTheme.chatViewFooterImgColor + hoveredColor: JamiTheme.showMoreButtonOpenColor + pressedColor: hoveredColor + + action: modelData + } + } + } } - Layout.maximumHeight: JamiTheme.chatViewFooterTextAreaMaximumHeight - marginSize / 2 - onSendMessagesRequired: root.sendMessageButtonClicked() - onTextChanged: MessagesAdapter.userIsComposing(text ? true : false) - } + Row { + + ListView { + id: listViewAction + + width: contentWidth + 2 * leftMargin + + Behavior on width { + NumberAnimation { + duration: JamiTheme.longFadeDuration + } + } + + 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<Action> 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: false + property bool needVideoDevice: false + property bool noSip: false + onTriggered: function clickAction() { + showMapClicked(); + } + } + ] + + ListModel { + id: listActions + Component.onCompleted: { + for (var i = 0; i < listViewAction.menuActions.length; i++) { + append({ + "menuAction": listViewAction.menuActions[i] + }); + } + } + } + + 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 + } + } - PushButton { - id: emojiButton - visible: WITH_WEBENGINE + Rectangle { + z: -1 + radius: 0 + color: showMoreButton.normalColor + width: JamiTheme.chatViewFooterButtonSize / 2 + height: JamiTheme.chatViewFooterButtonSize - Layout.alignment: Qt.AlignVCenter - Layout.rightMargin: sendMessageButton.visible ? 0 : marginSize - Layout.preferredWidth: JamiTheme.chatViewFooterButtonSize - Layout.preferredHeight: JamiTheme.chatViewFooterButtonSize + PushButton { + id: showMoreButton + anchors.left: parent.left - radius: JamiTheme.chatViewFooterButtonRadius - preferredSize: JamiTheme.chatViewFooterButtonIconSize + preferredSize: JamiTheme.chatViewFooterButtonSize + imageContainerWidth: 20 + imageContainerHeight: 20 - toolTipText: JamiStrings.addEmoji + radius: JamiTheme.chatViewFooterButtonRadius - source: JamiResources.emoji_black_24dp_svg + toolTipText: showDefault ? JamiStrings.showMore : JamiStrings.showLess - normalColor: JamiTheme.primaryBackgroundColor - imageColor: JamiTheme.messageWebViewFooterButtonImageColor + source: JamiResources.more_vert_24dp_svg - onClicked: root.emojiButtonClicked() + normalColor: showDefault ? JamiTheme.chatViewFooterListColor : JamiTheme.showMoreButtonOpenColor + imageColor: JamiTheme.chatViewFooterImgColor + pressedColor: JamiTheme.showMoreButtonOpenColor + hoveredColor: JamiTheme.showMoreButtonOpenColor - Component.onCompleted: JamiQmlUtils.emojiPickerButtonObj = emojiButton + onClicked: { + showDefault = !showDefault; + if (showTypo) + showTypo = false; + UtilsAdapter.setAppValue(Settings.Key.ShowMardownOption, showTypo); + UtilsAdapter.setAppValue(Settings.Key.ShowSendOption, !showDefault); + } + } + } + } } - PushButton { - id: sendMessageButton + Row { + id: sendButtonRow + spacing: JamiTheme.chatViewFooterRowSpacing + anchors.right: parent.right + anchors.rightMargin: sendMessageButton.visible ? marginSize : 0 + + PushButton { + id: sendMessageButton - objectName: "sendMessageButton" + objectName: "sendMessageButton" - Layout.alignment: Qt.AlignVCenter - Layout.rightMargin: visible ? marginSize : 0 - Layout.preferredWidth: scale * JamiTheme.chatViewFooterButtonSize - Layout.preferredHeight: JamiTheme.chatViewFooterButtonSize + width: scale * JamiTheme.chatViewFooterButtonSize + height: JamiTheme.chatViewFooterButtonSize - radius: JamiTheme.chatViewFooterButtonRadius - preferredSize: JamiTheme.chatViewFooterButtonIconSize - 6 + radius: JamiTheme.chatViewFooterButtonRadius + preferredSize: JamiTheme.chatViewFooterButtonIconSize - 6 + imageContainerWidth: 25 + imageContainerHeight: 25 - toolTipText: JamiStrings.send + toolTipText: JamiStrings.send - source: JamiResources.send_black_24dp_svg + source: JamiResources.send_black_24dp_svg - normalColor: JamiTheme.primaryBackgroundColor - imageColor: JamiTheme.messageWebViewFooterButtonImageColor + normalColor: JamiTheme.chatViewFooterSendButtonColor + imageColor: JamiTheme.chatViewFooterSendButtonImgColor + hoveredColor: JamiTheme.buttonTintedBlueHovered + pressedColor: hoveredColor - opacity: sendButtonVisibility ? 1 : 0 - visible: opacity - scale: opacity + opacity: sendButtonVisibility ? 1 : 0 + visible: opacity + scale: opacity - Behavior on opacity { - enabled: animate - NumberAnimation { - duration: JamiTheme.shortFadeDuration - easing.type: Easing.InOutQuad + Behavior on opacity { + enabled: animate + NumberAnimation { + duration: JamiTheme.shortFadeDuration + easing.type: Easing.InOutQuad + } } - } - onClicked: root.sendMessageButtonClicked() + onClicked: root.sendMessageButtonClicked() + } } - - Component.onCompleted: JamiQmlUtils.messageBarButtonsRowObj = messageBarRowLayout } } diff --git a/src/app/mainview/components/MessageBarTextArea.qml b/src/app/mainview/components/MessageBarTextArea.qml index 21b37f437..d3edc5691 100644 --- a/src/app/mainview/components/MessageBarTextArea.qml +++ b/src/app/mainview/components/MessageBarTextArea.qml @@ -27,12 +27,19 @@ JamiFlickable { property alias text: textArea.text property var textAreaObj: textArea property alias placeholderText: textArea.placeholderText + property alias selectedText: textArea.selectedText + property alias selectionStart: textArea.selectionStart + property alias selectionEnd: textArea.selectionEnd ScrollBar.vertical.visible: textArea.text ScrollBar.horizontal.visible: textArea.text signal sendMessagesRequired + function selectText(start, end) { + textArea.select(start, end); + } + function insertText(text) { textArea.insert(textArea.cursorPosition, text); } @@ -68,6 +75,8 @@ JamiFlickable { topPadding: 0 bottomPadding: 0 + persistentSelection: true + verticalAlignment: TextEdit.AlignVCenter font.pointSize: JamiTheme.textFontSize + 2 diff --git a/src/app/settingsview/SettingsSidePanel.qml b/src/app/settingsview/SettingsSidePanel.qml index 86479e6ae..5ca9ab64a 100644 --- a/src/app/settingsview/SettingsSidePanel.qml +++ b/src/app/settingsview/SettingsSidePanel.qml @@ -55,7 +55,8 @@ SidePanelBase { target: JamiQmlUtils function onSettingsPageRequested(index) { viewCoordinator.present("SettingsView"); - buttonGroup.checkedButton = buttonGroup.buttons[index]; + root.indexSelected(index); + root.currentIndex = index; } } -- GitLab