1
0
Fork 0
mirror of https://git.jami.net/savoirfairelinux/jami-client-qt.git synced 2025-08-03 14:25:38 +02:00

messagewebview: chatview message bar qml replacement - ui

1. New emoji picker by customizing emoji.js
2. New message bar ui (textarea, buttons, tooltips)
3. New pending files transfer container
4. Use MaterialToolTip for all PushButton

Change-Id: I05d0531c65c019ced42b04668a780919c8a4fac3
This commit is contained in:
Ming Rui Zhang 2021-06-30 09:53:06 -04:00
parent 96c0084c3b
commit 14620f8bc8
37 changed files with 1313 additions and 227 deletions

View file

@ -72,7 +72,8 @@ set(COMMON_SOURCES
${SRC_DIR}/conversationlistmodelbase.cpp
${SRC_DIR}/conversationlistmodel.cpp
${SRC_DIR}/searchresultslistmodel.cpp
${SRC_DIR}/calloverlaymodel.cpp)
${SRC_DIR}/calloverlaymodel.cpp
${SRC_DIR}/filestosendlistmodel.cpp)
set(COMMON_HEADERS
${SRC_DIR}/avatarimageprovider.h
@ -128,7 +129,8 @@ set(COMMON_HEADERS
${SRC_DIR}/conversationlistmodelbase.h
${SRC_DIR}/conversationlistmodel.h
${SRC_DIR}/searchresultslistmodel.h
${SRC_DIR}/calloverlaymodel.h)
${SRC_DIR}/calloverlaymodel.h
${SRC_DIR}/filestosendlistmodel.h)
set(QML_LIBS
Qt5::Quick

View file

@ -0,0 +1,22 @@
<?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>
<g>
<path d="M12,2.1c-5.4,0-9.9,4.4-9.9,9.9s4.4,9.9,9.9,9.9s9.9-4.4,9.9-9.9S17.4,2.1,12,2.1z M12,20.7c-4.8,0-8.7-3.9-8.7-8.7
S7.2,3.3,12,3.3s8.7,3.9,8.7,8.7S16.8,20.7,12,20.7z"/>
</g>
<g>
<path d="M7.4,13.3c-0.2,0-0.4,0.1-0.5,0.2c-0.1,0.1-0.1,0.3-0.1,0.5c0,0.1,0.1,0.3,0.2,0.4c1.4,1,3.1,1.5,4.9,1.5s3.4-0.5,4.9-1.5
c0.1-0.1,0.2-0.2,0.3-0.4c0-0.2,0-0.3-0.1-0.4c-0.2-0.3-0.5-0.3-0.8-0.1c-1.2,0.8-2.7,1.3-4.2,1.3s-3-0.4-4.2-1.3
C7.7,13.3,7.5,13.3,7.4,13.3z"/>
</g>
<g>
<path d="M8,8.9c-0.4,0-0.8,0.3-0.8,0.8c0,0.4,0.3,0.8,0.8,0.8s0.8-0.3,0.8-0.8C8.8,9.2,8.5,8.9,8,8.9z"/>
</g>
<g>
<path d="M16,8.9c-0.4,0-0.8,0.4-0.8,0.8c0,0.5,0.3,0.8,0.8,0.8c0.4,0,0.8-0.3,0.8-0.8C16.8,9.2,16.4,8.9,16,8.9z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -0,0 +1,8 @@
<?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 d="M14.2,2.3C14,2.1,13.7,2,13.4,2H5.5C4.8,2,4.3,2.5,4.3,3.2v6.3v1.6v9.7c0,0.7,0.5,1.2,1.2,1.2h13.1c0.7,0,1.2-0.5,1.2-1.2
V18V8.4c0-0.3-0.1-0.6-0.3-0.8L14.2,2.3z M18,7.7H14c0,0,0,0,0,0V3.7L18,7.7z M18.6,20.9C18.6,20.9,18.6,20.9,18.6,20.9l-13.1,0
c0,0,0,0,0,0v-9.7V9.5V3.2c0,0,0,0,0,0h7.4v4.5c0,0.7,0.5,1.2,1.2,1.2h4.5v9.2V20.9z"/>
</svg>

After

Width:  |  Height:  |  Size: 690 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 327 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 487 B

View file

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24px" height="24px"><path d="M0 0h24v24H0z" fill="none"/><path d="M6 2c-1.1 0-1.99.9-1.99 2L4 20c0 1.1.89 2 1.99 2H18c1.1 0 2-.9 2-2V8l-6-6H6zm7 7V3.5L18.5 9H13z"/></svg>

Before

Width:  |  Height:  |  Size: 237 B

View file

@ -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 d="M16,5.6c-0.4,0-0.7,0.4-0.7,0.7v11.1c0,1.8-1.5,3.3-3.3,3.3s-3.3-1.5-3.3-3.3V5.6c0-1.2,1-2.1,2.1-2.1C12,3.4,13,4.4,13,5.6
V16c0,0.5-0.4,0.9-0.9,0.9c-0.4,0-0.9-0.4-0.9-0.9V6.8c0-0.4-0.4-0.7-0.7-0.7c-0.4,0-0.7,0.3-0.7,0.7V16c0,1.2,1.1,2.3,2.3,2.3
s2.3-1.1,2.3-2.3V5.6c0-1.9-1.6-3.6-3.6-3.6S7.2,3.6,7.2,5.6v11.7c0,2.6,2.1,4.8,4.8,4.8s4.8-2.1,4.8-4.8v-11
C16.8,5.8,16.4,5.6,16,5.6z"/>
</svg>

After

Width:  |  Height:  |  Size: 743 B

View file

@ -1,13 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Message audio</title>
<g id="Icones_Outline" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Message-audio" stroke="#000000">
<path d="M12,2.875 C14.5197992,2.875 16.8010492,3.89635041 18.4523494,5.54765062 C20.1036496,7.19895083 21.125,9.48020083 21.125,12 L21.125,12 L21.125,21.125 L12,21.125 C9.48020083,21.125 7.19895083,20.1036496 5.54765062,18.4523494 C3.89635041,16.8010492 2.875,14.5197992 2.875,12 C2.875,9.48020083 3.89635041,7.19895083 5.54765062,5.54765062 C7.19895083,3.89635041 9.48020083,2.875 12,2.875 Z" id="Rectangle-Copy-3" stroke-width="1.75"></path>
<g id="Group" transform="translate(9.000000, 7.000000)" fill-rule="nonzero">
<path d="M3.2826376,0.724537696 C3.66238148,0.724537696 4.00643194,0.87901528 4.25561937,1.12820271 C4.5048068,1.37739014 4.65928439,1.7214406 4.65928439,2.10118448 L4.65928439,2.10118448 L4.65928439,5.11026918 C4.65928439,5.49001273 4.50480658,5.83406323 4.25561904,6.08325078 C4.00643165,6.33243816 3.66238135,6.48691596 3.2826376,6.48691596 C2.90289382,6.48691596 2.55884347,6.33243814 2.30965606,6.08325074 C2.0604685,5.8340632 1.90599067,5.49001272 1.90599067,5.11026918 L1.90599067,5.11026918 L1.90599067,2.10118448 C1.90599067,1.72144061 2.06046828,1.37739017 2.30965572,1.12820274 C2.55884318,0.879015295 2.90289369,0.724537696 3.2826376,0.724537696 Z" id="Path" stroke-width="1.35"></path>
<path d="M0.277829768,3.46892297 C0.131747046,3.46666758 -0.00228293577,3.60069619 -2.6215198e-05,3.74677891 L-2.6215198e-05,5.1145366 C-2.6215198e-05,6.83681201 1.32262269,8.24623865 3.00908469,8.38435551 L3.00908469,9.35033921 L1.91487307,9.35033921 C1.76379391,9.35033921 1.64132017,9.47280884 1.64132017,9.62389211 C1.64132017,9.77497538 1.76379391,9.89744502 1.91487307,9.89744502 L4.65040212,9.89744502 C4.80148129,9.89744502 4.92395503,9.77497538 4.92395503,9.62389211 C4.92395503,9.47280884 4.80148129,9.35064011 4.65040212,9.35033921 L3.5561905,9.35033921 L3.5561905,8.38435551 C5.24265237,8.24623865 6.56529592,6.83681201 6.56529592,5.1145366 L6.56529592,3.74677891 C6.56731043,3.60225818 6.43625533,3.46933062 6.29171955,3.46933062 C6.14718377,3.46933062 6.01612321,3.60225818 6.01816665,3.74677891 L6.01816665,5.1145366 C6.01816665,6.63475216 4.80285179,7.85006565 3.2826376,7.85006565 C1.76242204,7.85006565 0.547108409,6.63475216 0.547108409,5.1145366 L0.547108409,3.74677891 C0.549351543,3.60354661 0.421062069,3.47118667 0.277829768,3.46892297 Z" id="Path" stroke-width="0.75" fill="#000000"></path>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.7 KiB

View file

@ -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 d="M19.1,4.9C17.2,3,14.7,2,12,2S6.8,3,4.9,4.9S2,9.3,2,12s1,5.2,2.9,7.1S9.3,22,12,22h10V12C22,9.3,21,6.8,19.1,4.9z
M20.6,20.6H12c-2.3,0-4.4-0.9-6.1-2.5c-1.6-1.6-2.5-3.8-2.5-6.1s0.9-4.4,2.5-6.1C7.6,4.3,9.7,3.4,12,3.4s4.4,0.9,6.1,2.5
c1.6,1.6,2.5,3.8,2.5,6.1V20.6z"/>
<path d="M15,10.3c-0.1,0.1-0.2,0.2-0.2,0.4v1.4c0,1.4-1.1,2.5-2.5,2.5s-2.5-1.1-2.5-2.5v-1.4c0-0.1-0.1-0.3-0.2-0.4
c-0.1-0.1-0.2-0.2-0.4-0.2l0,0c-0.2,0-0.3,0.1-0.4,0.2c-0.1,0.1-0.2,0.2-0.2,0.4v1.4c0,1.8,1.3,3.3,3.1,3.6v0.5h-0.9
c-0.3,0-0.5,0.2-0.5,0.5s0.2,0.5,0.5,0.5h2.8c0.3,0,0.5-0.2,0.5-0.5s-0.2-0.5-0.5-0.5h-0.9v-0.5c1.7-0.3,3.1-1.8,3.1-3.6v-1.4
c0-0.1-0.1-0.3-0.2-0.4C15.5,10.2,15.2,10.1,15,10.3z M9.2,10.4L9.2,10.4L9.2,10.4L9.2,10.4L9.2,10.4z"/>
</g>
<g>
<path d="M12.3,13.9c-1,0-1.8-0.8-1.8-1.8V9c0-1,0.8-1.8,1.8-1.8S14.1,8,14.1,9v3.2C14.1,13.2,13.3,13.9,12.3,13.9z M12.3,8.4
c-0.3,0-0.6,0.2-0.6,0.6v3.2c0,0.3,0.2,0.6,0.6,0.6c0.3,0,0.6-0.2,0.6-0.6V9C12.9,8.7,12.6,8.4,12.3,8.4z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View file

@ -1,13 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Message video</title>
<g id="Icones_Outline" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Message-video" stroke="#000000">
<path d="M12,2.875 C14.5197992,2.875 16.8010492,3.89635041 18.4523494,5.54765062 C20.1036496,7.19895083 21.125,9.48020083 21.125,12 L21.125,12 L21.125,21.125 L12,21.125 C9.48020083,21.125 7.19895083,20.1036496 5.54765062,18.4523494 C3.89635041,16.8010492 2.875,14.5197992 2.875,12 C2.875,9.48020083 3.89635041,7.19895083 5.54765062,5.54765062 C7.19895083,3.89635041 9.48020083,2.875 12,2.875 Z" id="Rectangle-Copy-3" stroke-width="1.75"></path>
<g id="Ico_Camera" transform="translate(7.000000, 8.000000)" stroke-width="1.5">
<path d="M4.6832026,4.0582026 C5.29164453,3.875 5.4463271,3.94580015 5.55869578,4.05817556 C5.67108489,4.17057139 5.74188438,4.32529267 5.74188438,4.49598322 C5.74188438,4.66664052 5.67108115,4.8213337 5.55870252,4.93371234 C5.44633138,5.04608348 5.29164686,5.11688438 5.12098322,5.11688438 C4.95029879,5.11688438 4.7955881,5.04607082 4.68319586,4.93368531 C4.57081655,4.82131272 4.5,4.66663207 4.5,4.49598322 C4.5,4.32530112 4.57081281,4.17059238 4.6832026,4.0582026 Z" id="Path"></path>
<path d="M5.8691951,0.75 L6.46662157,1.94485294 L8.96139706,1.94485294 L9.04779412,7.28860294 L0.836397059,7.375 L0.75,2.03125 L3.33117255,1.94485294 L3.92859902,0.75 L5.8691951,0.75 Z" id="Path"></path>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.6 KiB

View file

@ -0,0 +1,20 @@
<?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>
<g id="Rectangle-Copy-3">
<path d="M22,22H12c-2.7,0-5.2-1-7.1-2.9C3,17.2,2,14.7,2,12c0-2.7,1-5.2,2.9-7.1S9.3,2,12,2c2.7,0,5.2,1,7.1,2.9
C21,6.8,22,9.3,22,12V22z M12,3.4c-2.3,0-4.4,0.9-6.1,2.5C4.3,7.6,3.4,9.7,3.4,12c0,2.3,0.9,4.4,2.5,6.1c1.6,1.6,3.8,2.5,6.1,2.5
h8.6V12c0-2.3-0.9-4.4-2.5-6.1C16.4,4.3,14.3,3.4,12,3.4z"/>
</g>
<g id="Ico_Camera" transform="translate(7.000000, 9.000000)">
<g id="Path">
<path d="M7.1,7.7H0.4c-0.8,0-1.2-0.5-1.2-1V0.3c0-0.4,0.4-0.9,1.1-1l6.7,0c0.7,0,1.1,0.5,1.1,1v0.6l1.1-0.6C9.6,0,10,0,10.3,0.2
c0.2,0.1,0.5,0.3,0.5,0.8v5c0,0.5-0.3,0.8-0.5,0.9C10,7,9.6,7,9.3,6.8L8.2,6.2v0.6C8.2,7.2,7.8,7.7,7.1,7.7z M0.5,6.4l6.4,0V5.1
c0-0.2,0.1-0.4,0.3-0.6c0.2-0.1,0.4-0.1,0.6,0l1.6,0.9V1.6L7.9,2.5c-0.2,0.1-0.4,0.1-0.6,0C7,2.4,6.9,2.2,6.9,1.9V0.6l-6.4,0V6.4
z M10,5.7L10,5.7C10,5.7,10,5.7,10,5.7z"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View file

@ -1,11 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Send</title>
<g id="Icones_Outline" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Send" fill-rule="nonzero" stroke="#000000" stroke-width="1.75">
<g id="noun_send_3383765" transform="translate(2.000000, 4.000000)">
<path d="M1.04917102,1.91025133 L18.2901355,8.17133814 L0.960533446,15.103179 L1.66342176,9.48007246 L7.92572464,9.48007246 C8.2924137,9.48007246 8.62438833,9.33144236 8.86469071,9.09113998 C9.10499308,8.85083761 9.25362319,8.51886297 9.25362319,8.15217391 C9.25362319,7.78548485 9.10499308,7.45351022 8.86469071,7.21320784 C8.62438833,6.97290547 8.2924137,6.82427536 7.92572464,6.82427536 L7.92572464,6.82427536 L1.66342207,6.82427536 L1.04917102,1.91025133 Z" id="Path"></path>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1,000 B

View file

@ -0,0 +1,12 @@
<?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="Send_Black_24dp">
<g id="noun_send_1433498" transform="translate(2.000000, 3.000000)">
<path id="Shape" d="M20,9c0-0.3-0.2-0.5-0.4-0.6L1.1-0.2C0.8-0.3,0.4-0.2,0.2,0s-0.3,0.6-0.1,0.9L4,9l-3.9,8.1
C-0.1,17.4,0,17.8,0.2,18c0.2,0.2,0.6,0.3,0.9,0.2l18.5-8.5C19.8,9.6,20,9.3,20,9L20,9z M17.4,9l-15,6.9l3.2-6.5
c0.1-0.2,0.1-0.5,0-0.7L2.4,2.1L17.4,9z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 725 B

View file

@ -1,11 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Link</title>
<g id="Icones" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Link" fill="#000000" fill-rule="nonzero" stroke="#000000" stroke-width="0.5">
<g id="noun_attach_998912" transform="translate(11.981262, 12.084524) rotate(25.000000) translate(-11.981262, -12.084524) translate(6.981262, 2.084524)">
<path d="M4.58333333,20 C2.05607096,20 0,17.943929 0,15.4166667 L0,3.33333333 C0,1.49536133 1.49536133,0 3.33333333,0 C5.17130533,0 6.66666667,1.49536133 6.66666667,3.33333333 L6.66666667,14.1666667 C6.66666667,15.3153483 5.73201496,16.25 4.58333333,16.25 C3.43465171,16.25 2.5,15.3153483 2.5,14.1666667 L2.5,4.56075033 C2.5,4.33064779 2.68636067,4.14408367 2.91666667,4.14408367 C3.14697267,4.14408367 3.33333333,4.33064779 3.33333333,4.56075033 L3.33333333,14.1666667 C3.33333333,14.855957 3.89404296,15.4166667 4.58333333,15.4166667 C5.27262371,15.4166667 5.83333333,14.855957 5.83333333,14.1666667 L5.83333333,3.33333333 C5.83333333,1.95475258 4.71191404,0.833333333 3.33333333,0.833333333 C1.95475262,0.833333333 0.833333333,1.95475263 0.833333333,3.33333333 L0.833333333,15.4166667 C0.833333333,17.4843343 2.51546225,19.1666667 4.58333333,19.1666667 C6.65120442,19.1666667 8.33333333,17.4843343 8.33333333,15.4166667 L8.33333333,4.04276529 C8.33333333,3.81266275 8.519694,3.62609863 8.75,3.62609863 C8.980306,3.62609863 9.16666667,3.81266275 9.16666667,4.04276529 L9.16666667,15.4166667 C9.16666667,17.943929 7.11059571,20 4.58333333,20 Z" id="Path"></path>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

View file

@ -146,5 +146,14 @@
<file>src/commoncomponents/contextmenu/GeneralMenuSeparator.qml</file>
<file>src/mainview/components/ParticipantOverlayButton.qml</file>
<file>src/mainview/components/ParticipantControlLayout.qml</file>
<file>src/mainview/components/MessageWebViewFooter.qml</file>
<file>src/commoncomponents/emojipicker/EmojiPicker.qml</file>
<file>src/commoncomponents/emojipicker/emojiPickerLoader.js</file>
<file>src/commoncomponents/emojipicker/emojiPickerLoader.html</file>
<file>src/commoncomponents/emojipicker/emoji.js</file>
<file>src/commoncomponents/JamiTextArea.qml</file>
<file>src/mainview/components/FilesToSendDelegate.qml</file>
<file>src/mainview/components/MessageBar.qml</file>
<file>src/mainview/components/FilesToSendContainer.qml</file>
</qresource>
</RCC>

View file

@ -60,7 +60,6 @@
<file>images/icons/ic_video_call_24px.svg</file>
<file>images/icons/ic_videocam_off_white_24dp.png</file>
<file>images/icons/ic_videocam_white.png</file>
<file>images/icons/ic_voicemail_white_24dp_2x.png</file>
<file>images/icons/ic_call_end_white_24px.svg</file>
<file>images/icons/round-add-24px.svg</file>
<file>images/icons/round-arrow_drop_down-24px.svg</file>
@ -84,7 +83,6 @@
<file>images/icons/round-add_a_photo-24px.svg</file>
<file>images/icons/ic_mic_white_24dp.png</file>
<file>images/icons/ic_play_white_24dp.png</file>
<file>images/icons/ic_voicemail_black_24dp_2x_.png</file>
<file>images/icons/av_icons/delete-24px.svg</file>
<file>images/icons/av_icons/fiber_manual_record-24px.svg</file>
<file>images/icons/av_icons/play_circle_outline-24px.svg</file>
@ -99,7 +97,6 @@
<file>images/icons/person-24px.svg</file>
<file>images/icons/drafts-24px.svg</file>
<file>images/icons/router-24px.svg</file>
<file>images/icons/insert_drive_file-24dp.svg</file>
<file>images/icons/arrow_back-white-24dp.svg</file>
<file>images/icons/videocam-24px.svg</file>
<file>images/icons/qr_code-24px.svg</file>
@ -122,10 +119,9 @@
<file>images/logo-jami-standard-coul-white.svg</file>
<file>images/icons/moderator.svg</file>
<file>images/icons/star_outline-24px.svg</file>
<file>images/icons/send_file-24px.svg</file>
<file>images/icons/message_video-24px.svg</file>
<file>images/icons/message_audio-24px.svg</file>
<file>images/icons/send-24px.svg</file>
<file>images/icons/message_audio_black-24dp.svg</file>
<file>images/icons/message_video_black-24dp.svg</file>
<file>images/icons/send_black-24dp.svg</file>
<file>images/icons/back-24px.svg</file>
<file>images/icons/place_audiocall-24px.svg</file>
<file>images/icons/add_people-24px.svg</file>
@ -146,5 +142,8 @@
<file>images/icons/spk_none_black_24dp.svg</file>
<file>images/icons/more_vert-24dp.svg</file>
<file>images/icons/chevron_left_black_24dp.svg</file>
<file>images/icons/emoji_black-24dp.svg</file>
<file>images/icons/link_black-24dp.svg</file>
<file>images/icons/file_black-24dp.svg</file>
</qresource>
</RCC>

View file

@ -0,0 +1,110 @@
/*
* Copyright (C) 2020 by Savoir-faire Linux
* Author: Mingrui Zhang <mingrui.zhang@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 2.14
import QtQuick.Controls 2.14
import net.jami.Constants 1.0
import "../commoncomponents/contextmenu"
Flickable {
id: root
property alias text: textArea.text
function insertText(text) {
textArea.insert(textArea.cursorPosition, text)
}
LineEditContextMenu {
id: textAreaContextMenu
lineEditObj: textArea
}
ScrollBar.vertical: ScrollBar {
policy: contentHeight > height ? ScrollBar.AlwaysOn : ScrollBar.AsNeeded
}
contentWidth: width
contentHeight: textArea.implicitHeight
interactive: true
clip: true
function ensureVisible(r) {
if (contentY >= r.y)
contentY = r.y
else if (contentY + height <= r.y + r.height)
contentY = r.y + r.height - height
}
TextArea.flickable: TextArea {
id: textArea
padding: 0
verticalAlignment: TextEdit.AlignVCenter
font.pointSize: JamiTheme.textFontSize + 2
font.hintingPreference: Font.PreferNoHinting
color: JamiTheme.textColor
renderType: Text.NativeRendering
wrapMode: TextEdit.Wrap
overwriteMode: true
selectByMouse: true
selectionColor: JamiTheme.placeHolderTextFontColor
textFormat: TextEdit.PlainText
placeholderTextColor: JamiTheme.placeHolderTextFontColor
cursorDelegate: Rectangle {
visible: textArea.cursorVisible
color: JamiTheme.textColor
width: 1
SequentialAnimation on opacity {
loops: Animation.Infinite
running: visible
NumberAnimation {
from: 1
to: 0
duration: JamiTheme.recordBlinkDuration
}
NumberAnimation {
from: 0
to: 1
duration: JamiTheme.recordBlinkDuration
}
}
}
background: Rectangle {
border.width: 0
color: JamiTheme.transparentColor
}
onReleased: {
if (event.button == Qt.RightButton)
textAreaContextMenu.openMenuAt(event)
}
onCursorRectangleChanged: root.ensureVisible(cursorRectangle)
}
}

View file

@ -27,6 +27,7 @@ Popup {
// convient access to closePolicy
property bool autoClose: true
property alias backgroundColor: container.color
onContentItemChanged: {
if(root.contentItem !== null)
@ -52,9 +53,7 @@ Popup {
background: Rectangle {
id: container
// TODO: this is the MaterialButton radius and should be part of
// a theme.
radius: 4
radius: JamiTheme.modalPopupRadius
width: root.width
height: root.height
}
@ -66,7 +65,7 @@ Popup {
horizontalOffset: 3.0
verticalOffset: 3.0
radius: container.radius * 4
samples: 16
samples: JamiTheme.modalPopupDropShadowSamples
color: JamiTheme.shadowColor
source: container
}

View file

@ -89,7 +89,7 @@ ItemDelegate {
id: preferenceFilePathDialog
title: JamiStrings.selectFile
folder: "file:///" + currentPath
folder: JamiQmlUtils.qmlFilePrefix + currentPath
onAccepted: {
var url = UtilsAdapter.getAbsPath(file.toString())

View file

@ -50,7 +50,7 @@ AbstractButton {
property alias textHAlign: textContent.horizontalAlignment
property bool buttonTextEnableElide: false
property string toolTipText: ""
property alias toolTipText: toolTip.text
// State colors
property string pressedColor: JamiTheme.pressedButtonColor
@ -80,9 +80,14 @@ AbstractButton {
hoverEnabled: true
focusPolicy: Qt.TabFocus
ToolTip.delay: Qt.styleHints.mousePressAndHoldInterval
ToolTip.visible: hovered && (toolTipText.length > 0)
ToolTip.text: toolTipText
MaterialToolTip {
id: toolTip
parent: root
visible: hovered && (toolTipText.length > 0)
delay: Qt.styleHints.mousePressAndHoldInterval
}
ResponsiveImage {
id: image

View file

@ -0,0 +1,128 @@
/*
* Copyright (C) 2020 by Savoir-faire Linux
* Author: Mingrui Zhang <mingrui.zhang@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 2.14
import QtQuick.Controls 2.14
import QtWebEngine 1.10
import QtWebChannel 1.14
import net.jami.Constants 1.0
import net.jami.Adapters 1.0
import "../"
ModalPopup {
id: root
signal emojiIsPicked(string content)
backgroundColor: JamiTheme.transparentColor
function openEmojiPicker() {
open()
emojiPickerWebView.runJavaScript(
"prepare_to_show(" + JamiTheme.darkTheme + ");")
}
onClosed: {
emojiPickerWebView.runJavaScript("prepare_to_hide();")
}
contentItem: Rectangle {
id: contentRect
implicitWidth: 400
implicitHeight: 425
color: JamiTheme.transparentColor
QtObject {
id: jsBridgeObject
// ID, under which this object will be known at chatview.js side.
WebChannel.id: "jsbridge"
// Functions that are exposed, return code can be derived from js side
// by setting callback function.
function emojiIsPicked(arg) {
root.emojiIsPicked(arg)
}
}
WebEngineView {
id: emojiPickerWebView
anchors.fill: contentRect
backgroundColor: JamiTheme.transparentColor
settings.javascriptEnabled: true
settings.javascriptCanOpenWindows: false
settings.javascriptCanAccessClipboard: true
settings.javascriptCanPaste: true
settings.fullScreenSupportEnabled: true
settings.allowRunningInsecureContent: true
settings.localContentCanAccessRemoteUrls: false
settings.localContentCanAccessFileUrls: false
settings.errorPageEnabled: false
settings.pluginsEnabled: false
settings.screenCaptureEnabled: false
settings.linksIncludedInFocusChain: false
settings.localStorageEnabled: true
webChannel: emojiPickerWebViewChannel
onLoadingChanged: {
if (loadRequest.status == WebEngineView.LoadSucceededStatus) {
emojiPickerWebView.runJavaScript(
UtilsAdapter.qStringFromFile(
":qwebchannel.js"))
emojiPickerWebView.runJavaScript(
UtilsAdapter.qStringFromFile(
":/src/commoncomponents/emojipicker/emoji.js"))
emojiPickerWebView.runJavaScript(
UtilsAdapter.qStringFromFile(
":/src/commoncomponents/emojipicker/emojiPickerLoader.js"))
emojiPickerWebView.runJavaScript(
"init_emoji_picker(" + JamiTheme.darkTheme + ");")
}
}
Component.onCompleted: {
profile.cachePath = UtilsAdapter.getCachePath()
profile.persistentStoragePath = UtilsAdapter.getCachePath()
profile.persistentCookiesPolicy = WebEngineProfile.NoPersistentCookies
profile.httpCacheType = WebEngineProfile.NoCache
profile.httpUserAgent = JamiStrings.httpUserAgentName
emojiPickerWebView.loadHtml(
UtilsAdapter.qStringFromFile(
":/src/commoncomponents/emojipicker/emojiPickerLoader.html"),
":/src/commoncomponents/emojipicker/emojiPickerLoader.html")
emojiPickerWebView.url
= "qrc:/src/commoncomponents/emojipicker/emojiPickerLoader.html"
}
}
// Provide WebChannel by registering jsBridgeObject.
WebChannel {
id: emojiPickerWebViewChannel
registeredObjects: [jsBridgeObject]
}
}
}

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,7 @@
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta charset="utf-8">
</head>
<body style="height: 100%; width: 100%; margin: 0; padding: 0%; overflow: hidden;"></body>
</html>

View file

@ -0,0 +1,47 @@
"use strict"
var emojiPicker = undefined
new QWebChannel(qt.webChannelTransport, function (channel) {
window.jsbridge = channel.objects.jsbridge
})
/* exported init_emoji_picker */
function init_emoji_picker(dark) {
emojiPicker = new EmojiButton({
theme: dark ? "dark" : "light"
})
emojiPicker.on("emoji", selection => {
window.jsbridge.emojiIsPicked(selection.emoji)
})
}
/* exported prepare_to_show */
function prepare_to_show(dark) {
emojiPicker.setTheme(dark ? "dark" : "light")
if (emojiPicker.hideInProgress) {
setTimeout(() => prepare_to_show(), 100)
return
}
emojiPicker.pickerVisible = true
emojiPicker.wrapper.style.display = 'block'
emojiPicker.focusTrap.activate()
emojiPicker.wrapper.style.height = '100%'
emojiPicker.wrapper.style.width = '100%'
setTimeout(() => {
emojiPicker.addEventListeners()
emojiPicker.setInitialFocus()
})
emojiPicker.emojiArea.reset()
}
/* exported prepare_to_hide */
function prepare_to_hide() {
emojiPicker.hidePicker()
}

View file

@ -24,6 +24,8 @@ import QtQuick 2.14
import net.jami.Adapters 1.0
Item {
property string qmlFilePrefix: "file:/"
readonly property string mainViewLoadPath: "qrc:/src/mainview/MainView.qml"
readonly property string wizardViewLoadPath: "qrc:/src/wizardview/WizardView.qml"
readonly property string base64StringTitle: "data:image/png;base64,"

View file

@ -487,4 +487,12 @@ Item {
property string isSwarm: qsTr("Is swarm:")
property string trueStr: qsTr("True")
property string falseStr: qsTr("False")
// Message view
property string addEmoji: qsTr("Add emoji")
property string sendFile: qsTr("Send file")
property string leaveAudioMessage: qsTr("Leave audio message")
property string leaveVideoMessage: qsTr("Leave video message")
property string send: qsTr("Send")
property string remove: qsTr("Remove")
}

View file

@ -158,6 +158,10 @@ Item {
property color previewImageBackgroundColor: whiteColor
property color previewCardContainerColor : darkTheme ? blackColor : whiteColor
property color previewUrlColor : darkTheme ? "#eeeeee" : "#333"
property color messageWebViewFooterButtonImageColor: darkTheme ? "#838383" : "#656565"
// Files To Send Container
property color removeFileButtonColor: Qt.rgba(96, 95, 97, 0.5)
// Font.
property color faddedFontColor: darkTheme? "#c0c0c0" : "#a0a0a0"
@ -245,7 +249,31 @@ Item {
property real lineEditContextMenuItemsWidth: 100
property real lineEditContextMenuSeparatorsHeight: 2
// main application spec
// Modal Popup
property real modalPopupRadius: 4
property real modalPopupDropShadowSamples: 16
// MessageWebView
property real messageWebViewHeaderPreferredHeight: 64
property real messageWebViewFooterPreferredHeight: 50
property real messageWebViewFooterMaximumHeight: 230
property real messageWebViewFooterRowSpacing: 1
property real messageWebViewFooterButtonSize: 36
property real messageWebViewFooterButtonIconSize: 48
property real messageWebViewFooterButtonRadius: 5
property real messageWebViewFooterFileContainerPreferredHeight: 150
property real messageWebViewFooterTextAreaMaximumHeight: 80
// MessageWebView File Transfer Container
property real filesToSendContainerSpacing: 5
property real filesToSendContainerPadding: 10
property real filesToSendDelegateWidth: 100
property real filesToSendDelegateHeight: 100
property real filesToSendDelegateRadius: 7
property real filesToSendDelegateButtonSize: 16
property real filesToSendDelegateFontPointSize: textFontSize + 2
// Main application spec
property real mainViewMinWidth: 300
property real mainViewMinHeight: 400

View file

@ -0,0 +1,106 @@
/*
* Copyright (C) 2021 by Savoir-faire Linux
* Author: Mingrui Zhang <mingrui.zhang@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 <http://www.gnu.org/licenses/>.
*/
#include "filestosendlistmodel.h"
#include "utils.h"
#include <QFileInfo>
#include <QImageReader>
FilesToSendListModel::FilesToSendListModel(QObject* parent)
: QAbstractListModel(parent)
{}
int
FilesToSendListModel::rowCount(const QModelIndex& parent) const
{
if (parent.isValid())
return 0;
return pendingFiles_.size();
}
QHash<int, QByteArray>
FilesToSendListModel::roleNames() const
{
using namespace FilesToSend;
QHash<int, QByteArray> roles;
#define X(role) roles[role] = #role;
FS_ROLES
#undef X
return roles;
}
Q_INVOKABLE void
FilesToSendListModel::addToPending(QString filePath)
{
auto fileInfo = QFileInfo(filePath);
if (!fileInfo.exists())
return;
// QImageReader will treat .gz file (Jami archive) as svgz image format
// so decideFormatFromContent is needed
bool isImage = false;
QImageReader reader;
reader.setDecideFormatFromContent(true);
reader.setFileName(filePath);
if (!reader.read().isNull())
isImage = true;
beginInsertRows(QModelIndex(), pendingFiles_.size(), pendingFiles_.size());
auto item = FilesToSend::Item(filePath, fileInfo.fileName(), isImage, fileInfo.size());
pendingFiles_.append(item);
endInsertRows();
}
void
FilesToSendListModel::removeFromPending(int index)
{
beginRemoveRows(QModelIndex(), index, index);
pendingFiles_.removeAt(index);
endRemoveRows();
}
Q_INVOKABLE void
FilesToSendListModel::flush()
{
beginRemoveRows(QModelIndex(), 0, pendingFiles_.size() - 1);
pendingFiles_.clear();
endRemoveRows();
}
QVariant
FilesToSendListModel::data(const QModelIndex& index, int role) const
{
using namespace FilesToSend;
auto item = pendingFiles_.at(index.row());
switch (role) {
case Role::FileName:
return QVariant(item.fileName);
case Role::FilePath:
return QVariant(item.filePath);
case Role::FileSize:
return QVariant(Utils::humanFileSize(item.fileSizeInByte));
case Role::IsImage:
return QVariant(item.isImage);
}
return QVariant();
}

View file

@ -0,0 +1,72 @@
/*
* Copyright (C) 2021 by Savoir-faire Linux
* Author: Mingrui Zhang <mingrui.zhang@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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <QAbstractListModel>
#include <QObject>
#define FS_ROLES \
X(FileName) \
X(FilePath) \
X(FileSize) \
X(IsImage)
namespace FilesToSend {
Q_NAMESPACE
enum Role {
DummyRole = Qt::UserRole + 1,
#define X(role) role,
FS_ROLES
#undef X
};
Q_ENUM_NS(Role)
struct Item
{
Item(QString filePath, QString fileName, bool isImage, qint64 fileSizeInByte)
: filePath(filePath)
, fileName(fileName)
, isImage(isImage)
, fileSizeInByte(fileSizeInByte)
{}
QString filePath;
QString fileName;
bool isImage;
qint64 fileSizeInByte;
};
} // namespace FilesToSend
class FilesToSendListModel : public QAbstractListModel
{
Q_OBJECT
public:
FilesToSendListModel(QObject* parent = nullptr);
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
QHash<int, QByteArray> roleNames() const override;
Q_INVOKABLE void addToPending(QString filePath);
Q_INVOKABLE void removeFromPending(int index);
Q_INVOKABLE void flush();
private:
QList<FilesToSend::Item> pendingFiles_;
};

View file

@ -0,0 +1,81 @@
/*
* Copyright (C) 2020 by Savoir-faire Linux
* Author: Mingrui Zhang <mingrui.zhang@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 2.14
import QtQuick.Controls 2.14
import QtQuick.Layouts 1.14
import net.jami.Models 1.0
import net.jami.Constants 1.0
Rectangle {
id: root
property alias filesToSendListModel: repeater.model
property alias filesToSendCount: repeater.count
color: JamiTheme.messageOutBgColor
ScrollView {
id: filesToSendContainerScrollView
anchors.fill: root
contentHeight: root.height
contentWidth: filesToSendContainerRow.width
ScrollBar.horizontal.visible: {
var ratio = filesToSendContainerRow.width / root.width
return ratio > 1
}
ScrollBar.horizontal.contentItem: Rectangle {
implicitHeight: 5
radius: width / 2
color: filesToSendContainerScrollView.ScrollBar.horizontal.pressed ?
JamiTheme.darkGreyColor : JamiTheme.whiteColor
}
ScrollBar.vertical.policy: ScrollBar.AlwaysOff
Row {
id: filesToSendContainerRow
anchors.centerIn: parent
spacing: JamiTheme.filesToSendContainerSpacing
padding: JamiTheme.filesToSendContainerPadding
Repeater {
id: repeater
delegate: FilesToSendDelegate {
anchors.verticalCenter: filesToSendContainerRow.verticalCenter
width: JamiTheme.filesToSendDelegateWidth
height: JamiTheme.filesToSendDelegateHeight
onRemoveFileButtonClicked: {
filesToSendListModel.removeFromPending(index)
}
}
model: FilesToSendListModel {
id: filesToSendListModel
}
}
}
}
}

View file

@ -0,0 +1,133 @@
/*
* Copyright (C) 2020 by Savoir-faire Linux
* Author: Mingrui Zhang <mingrui.zhang@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 2.14
import QtQuick.Controls 2.14
import QtQuick.Layouts 1.14
import QtGraphicalEffects 1.14
import net.jami.Constants 1.0
import net.jami.Models 1.0
import "../../commoncomponents"
Rectangle {
id: root
property real margin: 5
signal removeFileButtonClicked(int index)
radius: JamiTheme.filesToSendDelegateRadius
color: JamiTheme.messageInBgColor
ColumnLayout {
id: delegateFileWrapperColumnLayout
anchors.fill: parent
spacing: 0
visible: !IsImage
ResponsiveImage {
id: fileIcon
Layout.alignment: Qt.AlignTop | Qt.AlignLeft
Layout.topMargin: margin
Layout.leftMargin: margin
visible: !IsImage
source: "qrc:/images/icons/file_black-24dp.svg"
}
Text {
id: fileName
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
Layout.leftMargin: margin
Layout.preferredWidth: root.width - margin * 2
visible: !IsImage
font.pointSize: JamiTheme.filesToSendDelegateFontPointSize
text: FileName
elide: Text.ElideMiddle
}
Text {
id: fileSize
Layout.alignment: Qt.AlignBottom
Layout.leftMargin: margin
Layout.bottomMargin: margin
Layout.preferredWidth: root.width - margin * 2
visible: !IsImage
font.pointSize: JamiTheme.filesToSendDelegateFontPointSize
text: FileSize
elide: Text.ElideMiddle
}
}
AnimatedImage {
id: name
anchors.fill: parent
asynchronous: true
fillMode: Image.PreserveAspectCrop
source: IsImage ? JamiQmlUtils.qmlFilePrefix + FilePath : ""
layer.enabled: true
layer.effect: OpacityMask {
maskSource: Rectangle {
width: root.width
height: root.height
radius: JamiTheme.filesToSendDelegateRadius
}
}
}
PushButton {
id: removeFileButton
anchors.right: root.right
anchors.rightMargin: -margin
anchors.top: root.top
anchors.topMargin: -margin
radius: margin
preferredSize: JamiTheme.filesToSendDelegateButtonSize
toolTipText: JamiStrings.remove
source: "qrc:/images/icons/cross_black_24dp.svg"
normalColor: JamiTheme.removeFileButtonColor
hoveredColor: JamiTheme.lightGrey_
imageColor: JamiTheme.textColor
onClicked: root.removeFileButtonClicked(index)
}
}

View file

@ -0,0 +1,198 @@
/*
* Copyright (C) 2020 by Savoir-faire Linux
* Author: Mingrui Zhang <mingrui.zhang@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 2.14
import QtQuick.Controls 2.14
import QtQuick.Layouts 1.14
import net.jami.Adapters 1.0
import net.jami.Constants 1.0
import "../../commoncomponents"
RowLayout {
id: root
property var textAreaObj: textArea
property real marginSize: 10
signal sendFileButtonClicked
signal audioRecordMessageButtonClicked
signal videoRecordMessageButtonClicked
signal emojiButtonClicked
spacing: JamiTheme.messageWebViewFooterRowSpacing
PushButton {
id: sendFileButton
Layout.alignment: Qt.AlignVCenter
Layout.leftMargin: marginSize
Layout.preferredWidth: JamiTheme.messageWebViewFooterButtonSize
Layout.preferredHeight: JamiTheme.messageWebViewFooterButtonSize
radius: JamiTheme.messageWebViewFooterButtonRadius
preferredSize: JamiTheme.messageWebViewFooterButtonIconSize - 6
toolTipText: JamiStrings.sendFile
source: "qrc:/images/icons/link_black-24dp.svg"
normalColor: JamiTheme.primaryBackgroundColor
imageColor: JamiTheme.messageWebViewFooterButtonImageColor
onClicked: root.sendFileButtonClicked()
}
PushButton {
id: audioRecordMessageButton
Layout.alignment: Qt.AlignVCenter
Layout.preferredWidth: JamiTheme.messageWebViewFooterButtonSize
Layout.preferredHeight: JamiTheme.messageWebViewFooterButtonSize
radius: JamiTheme.messageWebViewFooterButtonRadius
preferredSize: JamiTheme.messageWebViewFooterButtonIconSize
toolTipText: JamiStrings.leaveAudioMessage
source: "qrc:/images/icons/message_audio_black-24dp.svg"
normalColor: JamiTheme.primaryBackgroundColor
imageColor: JamiTheme.messageWebViewFooterButtonImageColor
onClicked: root.audioRecordMessageButtonClicked()
}
PushButton {
id: videoRecordMessageButton
Layout.alignment: Qt.AlignVCenter
Layout.preferredWidth: JamiTheme.messageWebViewFooterButtonSize
Layout.preferredHeight: JamiTheme.messageWebViewFooterButtonSize
radius: JamiTheme.messageWebViewFooterButtonRadius
preferredSize: JamiTheme.messageWebViewFooterButtonIconSize
toolTipText: JamiStrings.leaveVideoMessage
source: "qrc:/images/icons/message_video_black-24dp.svg"
normalColor: JamiTheme.primaryBackgroundColor
imageColor: JamiTheme.messageWebViewFooterButtonImageColor
onClicked: root.videoRecordMessageButtonClicked()
}
JamiTextArea {
id: textArea
Layout.alignment: Qt.AlignVCenter
Layout.fillWidth: true
Layout.margins: marginSize / 2
Layout.preferredHeight: {
return JamiTheme.messageWebViewFooterPreferredHeight
> contentHeight ? JamiTheme.messageWebViewFooterPreferredHeight : contentHeight
}
Layout.maximumHeight: JamiTheme.messageWebViewFooterTextAreaMaximumHeight
- marginSize / 2
onTextChanged: {
if (text) {
sendMessageButton.visible = true
sendMessageButton.state = "buttonFadeOut"
} else
sendMessageButton.state = "buttonFadeIn"
}
}
PushButton {
id: emojiButton
Layout.alignment: Qt.AlignVCenter
Layout.rightMargin: sendMessageButton.visible ? 0 : marginSize
Layout.preferredWidth: JamiTheme.messageWebViewFooterButtonSize
Layout.preferredHeight: JamiTheme.messageWebViewFooterButtonSize
radius: JamiTheme.messageWebViewFooterButtonRadius
preferredSize: JamiTheme.messageWebViewFooterButtonIconSize
toolTipText: JamiStrings.addEmoji
source: "qrc:/images/icons/emoji_black-24dp.svg"
normalColor: JamiTheme.primaryBackgroundColor
imageColor: JamiTheme.messageWebViewFooterButtonImageColor
onClicked: root.emojiButtonClicked()
}
PushButton {
id: sendMessageButton
Layout.alignment: Qt.AlignVCenter
Layout.rightMargin: visible ? marginSize : 0
Layout.preferredWidth: JamiTheme.messageWebViewFooterButtonSize
Layout.preferredHeight: JamiTheme.messageWebViewFooterButtonSize
radius: JamiTheme.messageWebViewFooterButtonRadius
preferredSize: JamiTheme.messageWebViewFooterButtonIconSize - 6
toolTipText: JamiStrings.send
source: "qrc:/images/icons/send_black-24dp.svg"
normalColor: JamiTheme.primaryBackgroundColor
imageColor: JamiTheme.messageWebViewFooterButtonImageColor
opacity: 0
visible: false
states: [
State {
name: "buttonFadeIn"
PropertyChanges {
target: sendMessageButton
opacity: 0
}
},
State {
name: "buttonFadeOut"
PropertyChanges {
target: sendMessageButton
opacity: 1
}
}
]
transitions: Transition {
NumberAnimation {
properties: "opacity"
easing.type: Easing.InOutQuad
duration: 300
}
}
onOpacityChanged: {
if (opacity === 0)
visible = false
}
onClicked: {
}
}
}

View file

@ -30,11 +30,8 @@ import "../../commoncomponents"
import "../js/pluginhandlerpickercreation.js" as PluginHandlerPickerCreation
Rectangle {
id: messageWebViewRect
id: root
color: JamiTheme.backgroundColor
property int messageWebViewHeaderPreferredHeight: 64
property string headerUserAliasLabelText: ""
property string headerUserUserNameLabelText: ""
property bool jsLoaded: false
@ -69,13 +66,6 @@ Rectangle {
messageWebViewHeader.resetBackToWelcomeViewButtonSource(reset)
}
function setFilePathsToSend(filePaths) {
for (var index = 0; index < filePaths.length; ++index) {
var path = UtilsAdapter.getAbsPath(filePaths[index])
MessagesAdapter.setNewMessagesContent(path)
}
}
function updateChatviewTheme() {
var theme = 'setTheme("\
--svg-invert-percentage:' + JamiTheme.invertPercentageInDecimal + ';\
@ -107,6 +97,8 @@ Rectangle {
messageWebView.runJavaScript(theme);
}
color: JamiTheme.primaryBackgroundColor
Connections {
target: JamiTheme
@ -115,50 +107,6 @@ Rectangle {
}
}
JamiFileDialog {
id: jamiFileDialog
mode: JamiFileDialog.Mode.OpenFiles
onAccepted: setFilePathsToSend(jamiFileDialog.files)
}
MessageWebViewHeader {
DropArea{
anchors.fill: parent
onDropped: setFilePathsToSend(drop.urls)
}
id: messageWebViewHeader
anchors.top: messageWebViewRect.top
anchors.left: messageWebViewRect.left
width: messageWebViewRect.width
height: messageWebViewHeaderPreferredHeight
userAliasLabelText: headerUserAliasLabelText
userUserNameLabelText: headerUserUserNameLabelText
onBackClicked: {
MessagesAdapter.updateDraft()
mainView.showWelcomeView()
}
onNeedToHideConversationInCall: {
messageWebViewRect.needToHideConversationInCall()
}
onPluginSelector : {
// Create plugin handler picker - PLUGINS
PluginHandlerPickerCreation.createPluginHandlerPickerObjects(messageWebViewRect, false)
PluginHandlerPickerCreation.calculateCurrentGeo(
messageWebViewRect.width / 2, messageWebViewRect.height / 2)
PluginHandlerPickerCreation.openPluginHandlerPicker()
}
}
QtObject {
id: jsBridgeObject
@ -203,10 +151,6 @@ Rectangle {
MessagesAdapter.sendFile(arg)
}
function selectFile() {
jamiFileDialog.open()
}
function acceptInvitation() {
MessagesAdapter.acceptInvitation()
}
@ -220,11 +164,11 @@ Rectangle {
}
function emitMessagesCleared() {
messageWebViewRect.messagesCleared()
root.messagesCleared()
}
function emitMessagesLoaded() {
messageWebViewRect.messagesLoaded()
root.messagesLoaded()
}
function copyToDownloads(interactionId, displayName) {
@ -244,7 +188,7 @@ Rectangle {
}
function saveSendMessageContent(arg) {
messageWebViewRect.sendMessageContentSaved(arg)
root.sendMessageContentSaved(arg)
}
function onComposing(isComposing) {
@ -260,104 +204,152 @@ Rectangle {
}
}
WebEngineView {
id: messageWebView
anchors.top: messageWebViewHeader.bottom
anchors.topMargin: 1
anchors.left: messageWebViewRect.left
width: messageWebViewRect.width
height: messageWebViewRect.height - messageWebViewHeaderPreferredHeight
backgroundColor: "transparent"
settings.javascriptEnabled: true
settings.javascriptCanOpenWindows: true
settings.javascriptCanAccessClipboard: true
settings.javascriptCanPaste: true
settings.fullScreenSupportEnabled: true
settings.allowRunningInsecureContent: true
settings.localContentCanAccessRemoteUrls: true
settings.localContentCanAccessFileUrls: true
settings.errorPageEnabled: false
settings.pluginsEnabled: false
settings.screenCaptureEnabled: false
settings.linksIncludedInFocusChain: false
settings.localStorageEnabled: true
webChannel: messageWebViewChannel
DropArea{
anchors.fill: parent
onDropped: setFilePathsToSend(drop.urls)
}
onNavigationRequested: {
if(request.navigationType === WebEngineView.LinkClickedNavigation) {
MessagesAdapter.openUrl(request.url)
request.action = WebEngineView.IgnoreRequest
}
}
onLoadingChanged: {
if (loadRequest.status == WebEngineView.LoadSucceededStatus) {
messageWebView.runJavaScript(UtilsAdapter.getStyleSheet(
"chatcss",
UtilsAdapter.qStringFromFile(
":/chatview.css")))
messageWebView.runJavaScript(UtilsAdapter.getStyleSheet(
"chatwin",
UtilsAdapter.qStringFromFile(
":/chatview-qt.css")))
messageWebView.runJavaScript(UtilsAdapter.qStringFromFile(
":/linkify.js"))
messageWebView.runJavaScript(UtilsAdapter.qStringFromFile(
":/linkify-html.js"))
messageWebView.runJavaScript(UtilsAdapter.qStringFromFile(
":/linkify-string.js"))
messageWebView.runJavaScript(UtilsAdapter.qStringFromFile(
":/qwebchannel.js"))
messageWebView.runJavaScript(UtilsAdapter.qStringFromFile(
":/jed.js"))
messageWebView.runJavaScript(UtilsAdapter.qStringFromFile(
":/emoji.js"))
messageWebView.runJavaScript(UtilsAdapter.qStringFromFile(
":/previewInfo.js"))
messageWebView.runJavaScript(
UtilsAdapter.qStringFromFile(":/chatview.js"),
function() {
messageWebView.runJavaScript("init_i18n();")
MessagesAdapter.setDisplayLinks()
updateChatviewTheme()
messageWebView.runJavaScript("displayNavbar(false);")
jsLoaded = true
})
}
}
onContextMenuRequested: {
var needContextMenu = request.selectedText.length || request.isContentEditable
if (!needContextMenu)
request.accepted = true
}
Component.onCompleted: {
profile.cachePath = UtilsAdapter.getCachePath()
profile.persistentStoragePath = UtilsAdapter.getCachePath()
profile.persistentCookiesPolicy = WebEngineProfile.NoPersistentCookies
profile.httpCacheType = WebEngineProfile.NoCache
profile.httpUserAgent = JamiStrings.httpUserAgentName
messageWebView.loadHtml(UtilsAdapter.qStringFromFile(
":/chatview.html"), ":/chatview.html")
messageWebView.url = "qrc:/chatview.html"
}
}
// Provide WebChannel by registering jsBridgeObject.
WebChannel {
id: messageWebViewChannel
registeredObjects: [jsBridgeObject]
}
ColumnLayout {
anchors.fill: root
spacing: 0
MessageWebViewHeader {
id: messageWebViewHeader
Layout.alignment: Qt.AlignHCenter
Layout.fillWidth: true
Layout.preferredHeight: JamiTheme.messageWebViewHeaderPreferredHeight
Layout.maximumHeight: JamiTheme.messageWebViewHeaderPreferredHeight
userAliasLabelText: headerUserAliasLabelText
userUserNameLabelText: headerUserUserNameLabelText
DropArea{
anchors.fill: parent
//onDropped: setFilePathsToSend(drop.urls)
}
onBackClicked: {
MessagesAdapter.updateDraft()
mainView.showWelcomeView()
}
onNeedToHideConversationInCall: {
root.needToHideConversationInCall()
}
onPluginSelector : {
// Create plugin handler picker - PLUGINS
PluginHandlerPickerCreation.createPluginHandlerPickerObjects(root, false)
PluginHandlerPickerCreation.calculateCurrentGeo(root.width / 2, root.height / 2)
PluginHandlerPickerCreation.openPluginHandlerPicker()
}
}
WebEngineView {
id: messageWebView
Layout.alignment: Qt.AlignHCenter
Layout.fillWidth: true
Layout.fillHeight: true
Layout.topMargin: messageWebViewHeader.hairLineSize
Layout.bottomMargin: messageWebViewFooter.hairLineSize
backgroundColor: "transparent"
settings.javascriptEnabled: true
settings.javascriptCanOpenWindows: true
settings.javascriptCanAccessClipboard: true
settings.javascriptCanPaste: true
settings.fullScreenSupportEnabled: true
settings.allowRunningInsecureContent: true
settings.localContentCanAccessRemoteUrls: true
settings.localContentCanAccessFileUrls: true
settings.errorPageEnabled: false
settings.pluginsEnabled: false
settings.screenCaptureEnabled: false
settings.linksIncludedInFocusChain: false
settings.localStorageEnabled: true
webChannel: messageWebViewChannel
DropArea{
anchors.fill: parent
//onDropped: setFilePathsToSend(drop.urls)
}
onNavigationRequested: {
if(request.navigationType === WebEngineView.LinkClickedNavigation) {
MessagesAdapter.openUrl(request.url)
request.action = WebEngineView.IgnoreRequest
}
}
onLoadingChanged: {
if (loadRequest.status == WebEngineView.LoadSucceededStatus) {
messageWebView.runJavaScript(UtilsAdapter.getStyleSheet(
"chatcss",
UtilsAdapter.qStringFromFile(
":/chatview.css")))
messageWebView.runJavaScript(UtilsAdapter.getStyleSheet(
"chatwin",
UtilsAdapter.qStringFromFile(
":/chatview-qt.css")))
messageWebView.runJavaScript(UtilsAdapter.qStringFromFile(
":/linkify.js"))
messageWebView.runJavaScript(UtilsAdapter.qStringFromFile(
":/linkify-html.js"))
messageWebView.runJavaScript(UtilsAdapter.qStringFromFile(
":/linkify-string.js"))
messageWebView.runJavaScript(UtilsAdapter.qStringFromFile(
":/qwebchannel.js"))
messageWebView.runJavaScript(UtilsAdapter.qStringFromFile(
":/jed.js"))
messageWebView.runJavaScript(UtilsAdapter.qStringFromFile(
":/emoji.js"))
messageWebView.runJavaScript(UtilsAdapter.qStringFromFile(
":/previewInfo.js"))
messageWebView.runJavaScript(
UtilsAdapter.qStringFromFile(":/chatview.js"),
function() {
messageWebView.runJavaScript("init_i18n();")
MessagesAdapter.setDisplayLinks()
updateChatviewTheme()
messageWebView.runJavaScript("displayNavbar(false);")
messageWebView.runJavaScript("hideMessageBar(true);")
jsLoaded = true
})
}
}
onContextMenuRequested: {
var needContextMenu = request.selectedText.length || request.isContentEditable
if (!needContextMenu)
request.accepted = true
}
Component.onCompleted: {
profile.cachePath = UtilsAdapter.getCachePath()
profile.persistentStoragePath = UtilsAdapter.getCachePath()
profile.persistentCookiesPolicy = WebEngineProfile.NoPersistentCookies
profile.httpCacheType = WebEngineProfile.NoCache
profile.httpUserAgent = JamiStrings.httpUserAgentName
messageWebView.loadHtml(UtilsAdapter.qStringFromFile(
":/chatview.html"), ":/chatview.html")
messageWebView.url = "qrc:/chatview.html"
}
}
MessageWebViewFooter {
id: messageWebViewFooter
Layout.alignment: Qt.AlignHCenter
Layout.fillWidth: true
Layout.preferredHeight: implicitHeight
Layout.maximumHeight: JamiTheme.messageWebViewFooterMaximumHeight
}
}
}

View file

@ -0,0 +1,98 @@
/*
* Copyright (C) 2020 by Savoir-faire Linux
* Author: Mingrui Zhang <mingrui.zhang@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 2.14
import QtQuick.Controls 2.14
import QtQuick.Layouts 1.14
import net.jami.Models 1.0
import net.jami.Constants 1.0
import net.jami.Adapters 1.0
import "../../commoncomponents"
import "../../commoncomponents/emojipicker"
Rectangle {
id: root
property real hairLineSize: 1
function setFilePathsToSend(filePaths) {
for (var index = 0; index < filePaths.length; ++index) {
var path = UtilsAdapter.getAbsPath(filePaths[index])
dataTransferSendContainer.filesToSendListModel.addToPending(path)
}
}
implicitHeight: footerColumnLayout.implicitHeight
color: JamiTheme.primaryBackgroundColor
EmojiPicker {
id: emojiPicker
onEmojiIsPicked: messageBar.textAreaObj.insertText(content)
}
JamiFileDialog {
id: jamiFileDialog
mode: JamiFileDialog.Mode.OpenFiles
onAccepted: setFilePathsToSend(jamiFileDialog.files)
}
ColumnLayout {
id: footerColumnLayout
anchors.centerIn: root
width: root.width
spacing: 0
MessageBar {
id: messageBar
Layout.alignment: Qt.AlignHCenter
Layout.fillWidth: true
Layout.preferredHeight: implicitHeight
onEmojiButtonClicked: emojiPicker.openEmojiPicker()
onSendFileButtonClicked: jamiFileDialog.open()
}
FilesToSendContainer {
id: dataTransferSendContainer
Layout.alignment: Qt.AlignHCenter
Layout.fillWidth: true
Layout.preferredHeight: filesToSendCount ?
JamiTheme.messageWebViewFooterFileContainerPreferredHeight : 0
}
}
CustomBorder {
commonBorder: false
lBorderwidth: 0
rBorderwidth: 0
tBorderwidth: hairLineSize
bBorderwidth: 0
borderColor: JamiTheme.tabbarBorderColor
}
}

View file

@ -29,6 +29,7 @@ import "../../commoncomponents"
Rectangle {
id: messagingHeaderRect
property real hairLineSize: 1
property string userAliasLabelText
property string userUserNameLabelText
property string backToWelcomeViewButtonSource: "qrc:/images/icons/back-24px.svg"
@ -229,7 +230,7 @@ Rectangle {
lBorderwidth: 0
rBorderwidth: 0
tBorderwidth: 0
bBorderwidth: 1
bBorderwidth: hairLineSize
borderColor: JamiTheme.tabbarBorderColor
}
}

View file

@ -28,6 +28,7 @@
#include "deviceitemlistmodel.h"
#include "smartlistmodel.h"
#include "conversationlistmodelbase.h"
#include "filestosendlistmodel.h"
#include "appsettingsmanager.h"
#include "distantrenderer.h"
@ -105,6 +106,7 @@ registerTypes()
QML_REGISTERTYPE(NS_MODELS, VideoFormatResolutionModel);
QML_REGISTERTYPE(NS_MODELS, VideoFormatFpsModel);
QML_REGISTERTYPE(NS_MODELS, PluginListPreferenceModel);
QML_REGISTERTYPE(NS_MODELS, FilesToSendListModel);
QML_REGISTERTYPE(NS_MODELS, SmartListModel);
// Roles & type enums for models

View file

@ -820,7 +820,7 @@ Utils::humanFileSize(qint64 fileSize)
if (abs(fileSizeF) < thresh) {
return QString::number(fileSizeF) + " B";
}
QString units[] = {"kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"};
QString units[] = {"KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"};
int unit_position = -1;
do {
fileSizeF /= thresh;