mirror of
https://gitlab.linphone.org/BC/public/linphone-desktop.git
synced 2026-05-07 14:44:01 +00:00
Vocal message on send :
- Record - Play - Seek by clicking on the sound wave - Send with a text/file/reply - Improve ActionButton for horizontal progression and background color managment - Improve Icon with different height and width - Creation of MediaProgressBar
This commit is contained in:
parent
3ea4dbd4ec
commit
9f781aa434
36 changed files with 1081 additions and 60 deletions
|
|
@ -8,7 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
## Added
|
||||
- Features:
|
||||
* messages features : Reply, forward (to contact, to a SIP address or to a timeline)
|
||||
* messages features : Reply, forward (to contact, to a SIP address or to a timeline), Vocal record (on send)
|
||||
|
||||
## 4.3.2
|
||||
|
||||
|
|
|
|||
|
|
@ -181,6 +181,8 @@ set(SOURCES
|
|||
src/components/participant-imdn/ParticipantImdnStateProxyModel.cpp
|
||||
src/components/presence/OwnPresenceModel.cpp
|
||||
src/components/presence/Presence.cpp
|
||||
src/components/recorder/RecorderManager.cpp
|
||||
src/components/recorder/RecorderModel.cpp
|
||||
src/components/search/SearchHandler.cpp
|
||||
src/components/search/SearchResultModel.cpp
|
||||
src/components/search/SearchSipAddressesModel.cpp
|
||||
|
|
@ -288,6 +290,8 @@ set(HEADERS
|
|||
src/components/participant-imdn/ParticipantImdnStateProxyModel.cpp
|
||||
src/components/presence/OwnPresenceModel.hpp
|
||||
src/components/presence/Presence.hpp
|
||||
src/components/recorder/RecorderManager.hpp
|
||||
src/components/recorder/RecorderModel.hpp
|
||||
src/components/search/SearchHandler.hpp
|
||||
src/components/search/SearchResultModel.hpp
|
||||
src/components/search/SearchSipAddressesModel.hpp
|
||||
|
|
|
|||
47
linphone-app/assets/images/chat_audio_pause_custom.svg
Normal file
47
linphone-app/assets/images/chat_audio_pause_custom.svg
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="80"
|
||||
height="80"
|
||||
viewBox="0 0 80 80"
|
||||
version="1.1"
|
||||
id="svg8"
|
||||
sodipodi:docname="chat_audio_pause.svg"
|
||||
inkscape:version="1.1 (c68e22c387, 2021-05-23)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs12" />
|
||||
<sodipodi:namedview
|
||||
id="namedview10"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
showgrid="false"
|
||||
inkscape:zoom="5.3231707"
|
||||
inkscape:cx="28.460481"
|
||||
inkscape:cy="64.623139"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1043"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg8" />
|
||||
<g
|
||||
fill="none"
|
||||
fill-rule="evenodd"
|
||||
id="g6"
|
||||
transform="scale(0.96277665,0.97560976)">
|
||||
<g
|
||||
fill="#444444"
|
||||
id="g4">
|
||||
<path
|
||||
d="m 41.547,0 c 22.945,0 41.546,18.356 41.546,41 0,22.644 -18.6,41 -41.546,41 C 18.6,82 0,63.644 0,41 0,18.356 18.601,0 41.547,0 Z M 30.04,21.5 c -1.933,0 -3.5,1.567 -3.5,3.5 v 32 l 0.005,0.192 c 0.1,1.844 1.626,3.308 3.495,3.308 1.933,0 3.5,-1.567 3.5,-3.5 V 25 L 33.535,24.808 C 33.435,22.964 31.909,21.5 30.04,21.5 Z m 21,0 c -1.933,0 -3.5,1.567 -3.5,3.5 v 32 l 0.005,0.192 c 0.1,1.844 1.626,3.308 3.495,3.308 1.933,0 3.5,-1.567 3.5,-3.5 V 25 L 54.535,24.808 C 54.435,22.964 52.909,21.5 51.04,21.5 Z"
|
||||
id="path2" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.7 KiB |
47
linphone-app/assets/images/chat_audio_play_custom.svg
Normal file
47
linphone-app/assets/images/chat_audio_play_custom.svg
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="80"
|
||||
height="80"
|
||||
viewBox="0 0 80 80"
|
||||
version="1.1"
|
||||
id="svg8"
|
||||
sodipodi:docname="chat_audio_play.svg"
|
||||
inkscape:version="1.1 (c68e22c387, 2021-05-23)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs12" />
|
||||
<sodipodi:namedview
|
||||
id="namedview10"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
showgrid="false"
|
||||
inkscape:zoom="5.3231707"
|
||||
inkscape:cx="29.024055"
|
||||
inkscape:cy="63.683849"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1043"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg8" />
|
||||
<g
|
||||
fill="none"
|
||||
fill-rule="evenodd"
|
||||
id="g6"
|
||||
transform="scale(0.96277665,0.97560976)">
|
||||
<g
|
||||
fill="#444444"
|
||||
id="g4">
|
||||
<path
|
||||
d="m 41.547,0 c 22.945,0 41.546,18.356 41.546,41 0,22.644 -18.6,41 -41.546,41 C 18.6,82 0,63.644 0,41 0,18.356 18.601,0 41.547,0 Z M 29.975,20.97 V 59.812 L 61.75,41.12 Z"
|
||||
id="path2" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
48
linphone-app/assets/images/chat_audio_soundwave_custom.svg
Normal file
48
linphone-app/assets/images/chat_audio_soundwave_custom.svg
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="500"
|
||||
height="60"
|
||||
viewBox="0 0 500 60"
|
||||
version="1.1"
|
||||
id="svg8"
|
||||
sodipodi:docname="chat_audio_soundwave_custom.svg"
|
||||
inkscape:version="1.1 (c68e22c387, 2021-05-23)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs12" />
|
||||
<sodipodi:namedview
|
||||
id="namedview10"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
showgrid="false"
|
||||
inkscape:zoom="1.2704082"
|
||||
inkscape:cx="250.70682"
|
||||
inkscape:cy="-59.036143"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1043"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg8" />
|
||||
<g
|
||||
fill="none"
|
||||
fill-rule="evenodd"
|
||||
id="g6"
|
||||
transform="matrix(1.0204082,0,0,0.66666667,0,10)">
|
||||
<g
|
||||
fill="#444444"
|
||||
fill-rule="nonzero"
|
||||
id="g4">
|
||||
<path
|
||||
d="m 65,0 c 2.761,0 5,2.239 5,5 v 50 c 0,2.761 -2.239,5 -5,5 -2.761,0 -5,-2.239 -5,-5 V 5 c 0,-2.761 2.239,-5 5,-5 z m 120,0 c 2.761,0 5,2.239 5,5 v 50 c 0,2.761 -2.239,5 -5,5 -2.761,0 -5,-2.239 -5,-5 V 5 c 0,-2.761 2.239,-5 5,-5 z m 120,0 c 2.761,0 5,2.239 5,5 v 50 c 0,2.761 -2.239,5 -5,5 -2.761,0 -5,-2.239 -5,-5 V 5 c 0,-2.761 2.239,-5 5,-5 z m 120,0 c 2.761,0 5,2.239 5,5 v 50 c 0,2.761 -2.239,5 -5,5 -2.761,0 -5,-2.239 -5,-5 V 5 c 0,-2.761 2.239,-5 5,-5 z M 85,5 c 2.761,0 5,2.239 5,5 v 40 c 0,2.761 -2.239,5 -5,5 -2.761,0 -5,-2.239 -5,-5 V 10 c 0,-2.761 2.239,-5 5,-5 z m 120,0 c 2.761,0 5,2.239 5,5 v 40 c 0,2.761 -2.239,5 -5,5 -2.761,0 -5,-2.239 -5,-5 V 10 c 0,-2.761 2.239,-5 5,-5 z m 120,0 c 2.761,0 5,2.239 5,5 v 40 c 0,2.761 -2.239,5 -5,5 -2.761,0 -5,-2.239 -5,-5 V 10 c 0,-2.761 2.239,-5 5,-5 z m 120,0 c 2.761,0 5,2.239 5,5 v 40 c 0,2.761 -2.239,5 -5,5 -2.761,0 -5,-2.239 -5,-5 V 10 c 0,-2.761 2.239,-5 5,-5 z M 45,5 c 2.761,0 5,2.239 5,5 v 40 c 0,2.761 -2.239,5 -5,5 -2.761,0 -5,-2.239 -5,-5 V 10 c 0,-2.761 2.239,-5 5,-5 z m 120,0 c 2.761,0 5,2.239 5,5 v 40 c 0,2.761 -2.239,5 -5,5 -2.761,0 -5,-2.239 -5,-5 V 10 c 0,-2.761 2.239,-5 5,-5 z m 120,0 c 2.761,0 5,2.239 5,5 v 40 c 0,2.761 -2.239,5 -5,5 -2.761,0 -5,-2.239 -5,-5 V 10 c 0,-2.761 2.239,-5 5,-5 z m 120,0 c 2.761,0 5,2.239 5,5 v 40 c 0,2.761 -2.239,5 -5,5 -2.761,0 -5,-2.239 -5,-5 V 10 c 0,-2.761 2.239,-5 5,-5 z M 25,15 c 2.761,0 5,2.239 5,5 v 20 c 0,2.761 -2.239,5 -5,5 -2.761,0 -5,-2.239 -5,-5 V 20 c 0,-2.761 2.239,-5 5,-5 z m 120,0 c 2.761,0 5,2.239 5,5 v 20 c 0,2.761 -2.239,5 -5,5 -2.761,0 -5,-2.239 -5,-5 V 20 c 0,-2.761 2.239,-5 5,-5 z m 120,0 c 2.761,0 5,2.239 5,5 v 20 c 0,2.761 -2.239,5 -5,5 -2.761,0 -5,-2.239 -5,-5 V 20 c 0,-2.761 2.239,-5 5,-5 z m 120,0 c 2.761,0 5,2.239 5,5 v 20 c 0,2.761 -2.239,5 -5,5 -2.761,0 -5,-2.239 -5,-5 V 20 c 0,-2.761 2.239,-5 5,-5 z m -280,0 c 2.761,0 5,2.239 5,5 v 20 c 0,2.761 -2.239,5 -5,5 -2.761,0 -5,-2.239 -5,-5 V 20 c 0,-2.761 2.239,-5 5,-5 z m 120,0 c 2.761,0 5,2.239 5,5 v 20 c 0,2.761 -2.239,5 -5,5 -2.761,0 -5,-2.239 -5,-5 V 20 c 0,-2.761 2.239,-5 5,-5 z m 120,0 c 2.761,0 5,2.239 5,5 v 20 c 0,2.761 -2.239,5 -5,5 -2.761,0 -5,-2.239 -5,-5 V 20 c 0,-2.761 2.239,-5 5,-5 z m 120,0 c 2.761,0 5,2.239 5,5 v 20 c 0,2.761 -2.239,5 -5,5 -2.761,0 -5,-2.239 -5,-5 V 20 c 0,-2.761 2.239,-5 5,-5 z M 5,25 c 2.761,0 5,2.239 5,5 0,2.761 -2.239,5 -5,5 -2.761,0 -5,-2.239 -5,-5 0,-2.761 2.239,-5 5,-5 z m 120,0 c 2.761,0 5,2.239 5,5 0,2.761 -2.239,5 -5,5 -2.761,0 -5,-2.239 -5,-5 0,-2.761 2.239,-5 5,-5 z m 120,0 c 2.761,0 5,2.239 5,5 0,2.761 -2.239,5 -5,5 -2.761,0 -5,-2.239 -5,-5 0,-2.761 2.239,-5 5,-5 z m 120,0 c 2.761,0 5,2.239 5,5 0,2.761 -2.239,5 -5,5 -2.761,0 -5,-2.239 -5,-5 0,-2.761 2.239,-5 5,-5 z m 120,0 c 2.761,0 5,2.239 5,5 0,2.761 -2.239,5 -5,5 -2.761,0 -5,-2.239 -5,-5 0,-2.761 2.239,-5 5,-5 z"
|
||||
id="path2" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4 KiB |
51
linphone-app/assets/images/chat_audio_stop_custom.svg
Normal file
51
linphone-app/assets/images/chat_audio_stop_custom.svg
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="80"
|
||||
height="80"
|
||||
viewBox="0 0 80 80"
|
||||
version="1.1"
|
||||
id="svg10"
|
||||
sodipodi:docname="chat_audio_stop.svg"
|
||||
inkscape:version="1.1 (c68e22c387, 2021-05-23)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs14" />
|
||||
<sodipodi:namedview
|
||||
id="namedview12"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
showgrid="false"
|
||||
inkscape:zoom="5.3231707"
|
||||
inkscape:cx="6.2932417"
|
||||
inkscape:cy="62.368843"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1043"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg10" />
|
||||
<g
|
||||
fill="none"
|
||||
fill-rule="evenodd"
|
||||
id="g8"
|
||||
transform="scale(0.96167716,0.97560976)">
|
||||
<g
|
||||
fill="#444444"
|
||||
fill-rule="nonzero"
|
||||
id="g6">
|
||||
<g
|
||||
id="g4">
|
||||
<path
|
||||
d="m 41.594,0 c 22.972,0 41.594,18.356 41.594,41 0,22.644 -18.622,41 -41.594,41 C 18.622,82 0,63.644 0,41 0,18.356 18.622,0 41.594,0 Z m 16.5,23 h -32 c -1.105,0 -2,0.895 -2,2 v 32 c 0,1.105 0.895,2 2,2 h 32 c 1.104,0 2,-0.895 2,-2 V 25 c 0,-1.105 -0.896,-2 -2,-2 z"
|
||||
id="path2" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
|
|
@ -30,6 +30,10 @@
|
|||
<file>assets/images/cancel_custom.svg</file>
|
||||
<file>assets/images/chat_custom.svg</file>
|
||||
<file>assets/images/chat_amount.svg</file>
|
||||
<file>assets/images/chat_audio_pause_custom.svg</file>
|
||||
<file>assets/images/chat_audio_play_custom.svg</file>
|
||||
<file>assets/images/chat_audio_soundwave_custom.svg</file>
|
||||
<file>assets/images/chat_audio_stop_custom.svg</file>
|
||||
<file>assets/images/chat_count.svg</file>
|
||||
<file>assets/images/chat_delivered.svg</file>
|
||||
<file>assets/images/chat_error.svg</file>
|
||||
|
|
@ -193,6 +197,7 @@
|
|||
<file>ui/modules/Common/Helpers/InvertedMouseArea.qml</file>
|
||||
<file>ui/modules/Common/Image/Icon.qml</file>
|
||||
<file>ui/modules/Common/Image/RoundedImage.qml</file>
|
||||
<file>ui/modules/Common/Indicators/MediaProgressBar.qml</file>
|
||||
<file>ui/modules/Common/Indicators/VuMeter.qml</file>
|
||||
<file>ui/modules/Common/Menus/ApplicationMenuEntry.qml</file>
|
||||
<file>ui/modules/Common/Menus/ApplicationMenu.qml</file>
|
||||
|
|
@ -238,6 +243,7 @@
|
|||
<file>ui/modules/Common/Styles/Form/Tab/TabButtonStyle.qml</file>
|
||||
<file>ui/modules/Common/Styles/Form/Tab/TabContainerStyle.qml</file>
|
||||
<file>ui/modules/Common/Styles/Form/TransparentTextInputStyle.qml</file>
|
||||
<file>ui/modules/Common/Styles/Indicators/MediaProgressBarStyle.qml</file>
|
||||
<file>ui/modules/Common/Styles/Indicators/VuMeterStyle.qml</file>
|
||||
<file>ui/modules/Common/Styles/Menus/ApplicationMenuStyle.qml</file>
|
||||
<file>ui/modules/Common/Styles/Menus/DropDownStaticMenuStyle.qml</file>
|
||||
|
|
@ -270,6 +276,7 @@
|
|||
<file>ui/modules/Linphone/Chat/Chat.qml</file>
|
||||
<file>ui/modules/Linphone/Chat/ChatDeliveries.qml</file>
|
||||
<file>ui/modules/Linphone/Chat/ChatMenu.qml</file>
|
||||
<file>ui/modules/Linphone/Chat/ChatAudioPreview.qml</file>
|
||||
<file>ui/modules/Linphone/Chat/ChatMessagePreview.qml</file>
|
||||
<file>ui/modules/Linphone/Chat/ChatForwardMessage.qml</file>
|
||||
<file>ui/modules/Linphone/Chat/ChatReplyMessage.qml</file>
|
||||
|
|
@ -314,6 +321,7 @@
|
|||
<file>ui/modules/Linphone/Styles/Calls/CallStatisticsStyle.qml</file>
|
||||
<file>ui/modules/Linphone/Styles/Calls/ConferenceControlsStyle.qml</file>
|
||||
<file>ui/modules/Linphone/Styles/Chat/ChatStyle.qml</file>
|
||||
<file>ui/modules/Linphone/Styles/Chat/ChatAudioPreviewStyle.qml</file>
|
||||
<file>ui/modules/Linphone/Styles/Chat/ChatForwardMessageStyle.qml</file>
|
||||
<file>ui/modules/Linphone/Styles/Chat/ChatReplyMessageStyle.qml</file>
|
||||
<file>ui/modules/Linphone/Styles/Codecs/CodecsViewerStyle.qml</file>
|
||||
|
|
|
|||
|
|
@ -533,6 +533,14 @@ static inline void registerSharedSingletonType (const char *name) {
|
|||
qmlRegisterSingletonType<T>(Constants::MainQmlUri, 1, 0, name, makeSharedSingleton<T, function>);
|
||||
}
|
||||
|
||||
template<typename T, T *(CoreManager::*function)()>
|
||||
static QObject *makeSharedSingleton (QQmlEngine *, QJSEngine *) {
|
||||
QObject *object = (CoreManager::getInstance()->*function)();
|
||||
QQmlEngine::setObjectOwnership(object, QQmlEngine::CppOwnership);
|
||||
return object;
|
||||
}
|
||||
|
||||
|
||||
template<typename T, T *(CoreManager::*function)() const>
|
||||
static QObject *makeSharedSingleton (QQmlEngine *, QJSEngine *) {
|
||||
QObject *object = (CoreManager::getInstance()->*function)();
|
||||
|
|
@ -545,6 +553,11 @@ static inline void registerSharedSingletonType (const char *name) {
|
|||
qmlRegisterSingletonType<T>(Constants::MainQmlUri, 1, 0, name, makeSharedSingleton<T, function>);
|
||||
}
|
||||
|
||||
template<typename T, T *(CoreManager::*function)()>
|
||||
static inline void registerSharedSingletonType (const char *name) {
|
||||
qmlRegisterSingletonType<T>(Constants::MainQmlUri, 1, 0, name, makeSharedSingleton<T, function>);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline void registerUncreatableType (const char *name) {
|
||||
qmlRegisterUncreatableType<T>(Constants::MainQmlUri, 1, 0, name, QLatin1String("Uncreatable"));
|
||||
|
|
@ -647,6 +660,7 @@ void App::registerTypes () {
|
|||
registerUncreatableType<ContentModel>("ContentModel");
|
||||
registerUncreatableType<HistoryModel>("HistoryModel");
|
||||
registerUncreatableType<LdapModel>("LdapModel");
|
||||
registerUncreatableType<RecorderModel>("RecorderModel");
|
||||
registerUncreatableType<SearchResultModel>("SearchResultModel");
|
||||
registerUncreatableType<SipAddressObserver>("SipAddressObserver");
|
||||
registerUncreatableType<VcardModel>("VcardModel");
|
||||
|
|
@ -680,6 +694,7 @@ void App::registerSharedTypes () {
|
|||
registerSharedSingletonType<ContactsImporterListModel, &CoreManager::getContactsImporterListModel>("ContactsImporterListModel");
|
||||
registerSharedSingletonType<LdapListModel, &CoreManager::getLdapListModel>("LdapListModel");
|
||||
registerSharedSingletonType<TimelineListModel, &CoreManager::getTimelineListModel>("TimelineListModel");
|
||||
registerSharedSingletonType<RecorderManager, &CoreManager::getRecorderManager>("RecorderManager");
|
||||
|
||||
//qmlRegisterSingletonType<ColorListModel>(Constants::MainQmlUri, 1, 0, "ColorList", mColorListModel);
|
||||
|
||||
|
|
|
|||
|
|
@ -63,6 +63,8 @@
|
|||
#include "participant-imdn/ParticipantImdnStateListModel.hpp"
|
||||
#include "participant-imdn/ParticipantImdnStateProxyModel.hpp"
|
||||
#include "presence/OwnPresenceModel.hpp"
|
||||
#include "recorder/RecorderModel.hpp"
|
||||
#include "recorder/RecorderManager.hpp"
|
||||
#include "settings/AccountSettingsModel.hpp"
|
||||
#include "settings/SettingsModel.hpp"
|
||||
#include "search/SearchResultModel.hpp"
|
||||
|
|
|
|||
|
|
@ -52,6 +52,8 @@
|
|||
#include "components/participant/ParticipantModel.hpp"
|
||||
#include "components/participant/ParticipantListModel.hpp"
|
||||
#include "components/presence/Presence.hpp"
|
||||
#include "components/recorder/RecorderManager.hpp"
|
||||
#include "components/recorder/RecorderModel.hpp"
|
||||
#include "components/timeline/TimelineModel.hpp"
|
||||
#include "components/timeline/TimelineListModel.hpp"
|
||||
#include "components/core/event-count-notifier/AbstractEventCountNotifier.hpp"
|
||||
|
|
@ -600,6 +602,7 @@ void ChatRoomModel::setReply(ChatMessageModel * model){
|
|||
void ChatRoomModel::clearReply(){
|
||||
mReply = nullptr;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------
|
||||
|
||||
void ChatRoomModel::deleteChatRoom(){
|
||||
|
|
@ -639,13 +642,18 @@ void ChatRoomModel::updateParticipants(const QVariantList& participants){
|
|||
|
||||
void ChatRoomModel::sendMessage (const QString &message) {
|
||||
shared_ptr<linphone::ChatMessage> _message;
|
||||
if(mReply){
|
||||
if(mReply)
|
||||
_message = mChatRoom->createReplyMessage(mReply);
|
||||
_message->addUtf8TextContent(message.toUtf8().toStdString());
|
||||
}else{
|
||||
_message= mChatRoom->createMessageFromUtf8(message.toUtf8().toStdString());
|
||||
else
|
||||
_message= mChatRoom->createEmptyMessage();
|
||||
auto recorder = CoreManager::getInstance()->getRecorderManager();
|
||||
if(recorder->haveVocalRecorder()) {
|
||||
auto content = recorder->getVocalRecorder()->getRecorder()->createContent();
|
||||
if(content)
|
||||
_message->addContent(content);
|
||||
}
|
||||
|
||||
if(!message.isEmpty())
|
||||
_message->addUtf8TextContent(message.toUtf8().toStdString());
|
||||
_message->send();
|
||||
emit messageSent(_message);
|
||||
}
|
||||
|
|
@ -677,6 +685,13 @@ void ChatRoomModel::sendFileMessage (const QString &path) {
|
|||
|
||||
shared_ptr<linphone::ChatMessage> message = mChatRoom->createFileTransferMessage(content);
|
||||
message->getContents().front()->setFilePath(Utils::appStringToCoreString(path));
|
||||
|
||||
auto recorder = CoreManager::getInstance()->getRecorderManager();
|
||||
if(recorder->haveVocalRecorder()) {
|
||||
auto content = recorder->getVocalRecorder()->getRecorder()->createContent();
|
||||
if(content)
|
||||
message->addContent(content);
|
||||
}
|
||||
message->send();
|
||||
|
||||
emit messageSent(message);
|
||||
|
|
@ -686,6 +701,12 @@ void ChatRoomModel::forwardMessage(ChatMessageModel * model){
|
|||
if(model){
|
||||
shared_ptr<linphone::ChatMessage> _message;
|
||||
_message = mChatRoom->createForwardMessage(model->getChatMessage());
|
||||
auto recorder = CoreManager::getInstance()->getRecorderManager();
|
||||
if(recorder->haveVocalRecorder()) {
|
||||
auto content = recorder->getVocalRecorder()->getRecorder()->createContent();
|
||||
if(content)
|
||||
_message->addContent(content);
|
||||
}
|
||||
_message->send();
|
||||
emit messageSent(_message);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@
|
|||
#include "components/contacts/ContactsImporterListModel.hpp"
|
||||
#include "components/history/HistoryModel.hpp"
|
||||
#include "components/ldap/LdapListModel.hpp"
|
||||
#include "components/recorder/RecorderManager.hpp"
|
||||
#include "components/settings/AccountSettingsModel.hpp"
|
||||
#include "components/settings/SettingsModel.hpp"
|
||||
#include "components/sip-addresses/SipAddressesModel.hpp"
|
||||
|
|
@ -123,6 +124,14 @@ HistoryModel* CoreManager::getHistoryModel(){
|
|||
}
|
||||
return mHistoryModel;
|
||||
}
|
||||
|
||||
RecorderManager* CoreManager::getRecorderManager(){
|
||||
if(!mRecorderManager){
|
||||
mRecorderManager = new RecorderManager(this);
|
||||
emit recorderManagerCreated(mRecorderManager);
|
||||
}
|
||||
return mRecorderManager;
|
||||
}
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void CoreManager::init (QObject *parent, const QString &configPath) {
|
||||
|
|
@ -183,6 +192,7 @@ void CoreManager::cleanLogs () const {
|
|||
|
||||
mCore->resetLogCollection();
|
||||
}
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ class CoreHandlers;
|
|||
class EventCountNotifier;
|
||||
class HistoryModel;
|
||||
class LdapListModel;
|
||||
class RecorderManager;
|
||||
class SettingsModel;
|
||||
class SipAddressesModel;
|
||||
class VcardModel;
|
||||
|
|
@ -76,6 +77,7 @@ public:
|
|||
//bool chatRoomModelExists (std::shared_ptr<linphone::ChatRoom> chatRoom);
|
||||
|
||||
HistoryModel* getHistoryModel();
|
||||
RecorderManager* getRecorderManager();
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Video render lock.
|
||||
|
|
@ -179,6 +181,7 @@ signals:
|
|||
|
||||
void chatRoomModelCreated (const std::shared_ptr<ChatRoomModel> &chatRoomModel);
|
||||
void historyModelCreated (HistoryModel *historyModel);
|
||||
void recorderManagerCreated(RecorderManager *recorderModel);
|
||||
|
||||
void logsUploaded (const QString &url);
|
||||
|
||||
|
|
@ -227,6 +230,7 @@ private:
|
|||
//QList<QPair<std::shared_ptr<linphone::ChatRoom>, std::weak_ptr<ChatRoomModel>>> mChatRoomModels;
|
||||
HistoryModel * mHistoryModel = nullptr;
|
||||
LdapListModel *mLdapListModel = nullptr;
|
||||
RecorderManager* mRecorderManager = nullptr;
|
||||
|
||||
QTimer *mCbsTimer = nullptr;
|
||||
|
||||
|
|
|
|||
71
linphone-app/src/components/recorder/RecorderManager.cpp
Normal file
71
linphone-app/src/components/recorder/RecorderManager.cpp
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Copyright (c) 2021 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of linphone-desktop
|
||||
* (see https://www.linphone.org).
|
||||
*
|
||||
* 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 <QQmlApplicationEngine>
|
||||
#include <QTimer>
|
||||
|
||||
#include "app/App.hpp"
|
||||
#include "components/core/CoreManager.hpp"
|
||||
|
||||
#include "RecorderManager.hpp"
|
||||
#include "RecorderModel.hpp"
|
||||
|
||||
// =============================================================================
|
||||
|
||||
RecorderManager::RecorderManager (QObject * parent) : QObject(parent) {
|
||||
App::getInstance()->getEngine()->setObjectOwnership(this, QQmlEngine::CppOwnership);// Avoid QML to destroy it when passing by Q_INVOKABLE
|
||||
}
|
||||
|
||||
RecorderManager::~RecorderManager(){
|
||||
}
|
||||
|
||||
|
||||
bool RecorderManager::haveVocalRecorder() const{
|
||||
return mVocalRecorder != nullptr;
|
||||
}
|
||||
|
||||
RecorderModel* RecorderManager::getVocalRecorder(){
|
||||
if( !mVocalRecorder) {
|
||||
auto core = CoreManager::getInstance()->getCore();
|
||||
std::shared_ptr<linphone::RecorderParams> params = core->createRecorderParams();
|
||||
params->setFileFormat(linphone::RecorderFileFormat::Mkv);
|
||||
params->setVideoCodec("");
|
||||
auto recorder = core->createRecorder(params);
|
||||
if(recorder)
|
||||
mVocalRecorder = RecorderModel::create(recorder, this);
|
||||
emit haveVocalRecorderChanged();
|
||||
}
|
||||
return mVocalRecorder.get();
|
||||
}
|
||||
|
||||
RecorderModel* RecorderManager::resetVocalRecorder(){
|
||||
if(mVocalRecorder)
|
||||
clearVocalRecorder();
|
||||
return getVocalRecorder();
|
||||
}
|
||||
|
||||
void RecorderManager::clearVocalRecorder(){
|
||||
if( mVocalRecorder){
|
||||
mVocalRecorder = nullptr;
|
||||
emit haveVocalRecorderChanged();
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
50
linphone-app/src/components/recorder/RecorderManager.hpp
Normal file
50
linphone-app/src/components/recorder/RecorderManager.hpp
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright (c) 2021 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of linphone-desktop
|
||||
* (see https://www.linphone.org).
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef RECORDER_MANAGER_MODEL_H
|
||||
#define RECORDER_MANAGER_MODEL_H
|
||||
|
||||
|
||||
#include <linphone++/linphone.hh>
|
||||
#include <QObject>
|
||||
|
||||
// =============================================================================
|
||||
class RecorderModel;
|
||||
|
||||
class RecorderManager : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
RecorderManager (QObject * parent = nullptr);
|
||||
virtual ~RecorderManager();
|
||||
|
||||
Q_PROPERTY(bool haveVocalRecorder READ haveVocalRecorder NOTIFY haveVocalRecorderChanged)
|
||||
|
||||
bool haveVocalRecorder() const;
|
||||
Q_INVOKABLE RecorderModel* getVocalRecorder();
|
||||
Q_INVOKABLE RecorderModel* resetVocalRecorder();
|
||||
Q_INVOKABLE void clearVocalRecorder();
|
||||
|
||||
signals:
|
||||
void haveVocalRecorderChanged();
|
||||
|
||||
private:
|
||||
std::shared_ptr<RecorderModel> mVocalRecorder;
|
||||
};
|
||||
#endif
|
||||
95
linphone-app/src/components/recorder/RecorderModel.cpp
Normal file
95
linphone-app/src/components/recorder/RecorderModel.cpp
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* Copyright (c) 2021 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of linphone-desktop
|
||||
* (see https://www.linphone.org).
|
||||
*
|
||||
* 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 <QQmlApplicationEngine>
|
||||
#include <QFile>
|
||||
|
||||
#include "app/App.hpp"
|
||||
#include "app/paths/Paths.hpp"
|
||||
#include "components/core/CoreManager.hpp"
|
||||
#include "components/settings/SettingsModel.hpp"
|
||||
#include "utils/Utils.hpp"
|
||||
|
||||
#include "RecorderModel.hpp"
|
||||
|
||||
// =============================================================================
|
||||
|
||||
RecorderModel::RecorderModel ( std::shared_ptr<linphone::Recorder> recorder, QObject * parent) : QObject(parent) {
|
||||
App::getInstance()->getEngine()->setObjectOwnership(this, QQmlEngine::CppOwnership);// Avoid QML to destroy it when passing by Q_INVOKABLE
|
||||
mRecorder= recorder;
|
||||
}
|
||||
|
||||
RecorderModel::~RecorderModel(){
|
||||
}
|
||||
|
||||
std::shared_ptr<RecorderModel> RecorderModel::create(std::shared_ptr<linphone::Recorder> recorder, QObject * parent){
|
||||
return std::make_shared<RecorderModel>(recorder, parent);
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<linphone::Recorder> RecorderModel::getRecorder(){
|
||||
return mRecorder;
|
||||
}
|
||||
|
||||
int RecorderModel::getDuration()const{
|
||||
return mRecorder->getDuration();
|
||||
}
|
||||
|
||||
LinphoneEnums::RecorderState RecorderModel::getState() const{
|
||||
return LinphoneEnums::fromLinphone(mRecorder->getState());
|
||||
}
|
||||
|
||||
QString RecorderModel::getFile()const{
|
||||
return Utils::coreStringToAppString(mRecorder->getFile());
|
||||
}
|
||||
|
||||
void RecorderModel::start(){
|
||||
bool soFarSoGood;
|
||||
QString filename = QStringLiteral("vocal_%1.mkv")
|
||||
.arg(QDateTime::currentDateTime().toString("yyyy-MM-dd_hh-mm-ss-zzz"));
|
||||
const QString safeFilePath = Utils::getSafeFilePath(
|
||||
QStringLiteral("%1%2")
|
||||
.arg(Utils::coreStringToAppString(Paths::getCapturesDirPath()))
|
||||
.arg(filename),
|
||||
&soFarSoGood
|
||||
);
|
||||
|
||||
if (!soFarSoGood) {
|
||||
qWarning() << QStringLiteral("Unable to create safe file path for: %1.").arg(filename);
|
||||
}else if(mRecorder->open(Utils::appStringToCoreString(safeFilePath)) < 0)
|
||||
qWarning() << QStringLiteral("Unable to open safe file path for: %1.").arg(filename);
|
||||
else if( mRecorder->start() < 0)
|
||||
qWarning() << QStringLiteral("Unable to start recording to : %1.").arg(filename);
|
||||
emit stateChanged();
|
||||
emit fileChanged();
|
||||
}
|
||||
|
||||
void RecorderModel::pause(){
|
||||
qWarning() << mRecorder->pause();
|
||||
emit stateChanged();
|
||||
}
|
||||
|
||||
void RecorderModel::stop(){
|
||||
if(mRecorder->pause() == 0)
|
||||
mRecorder->close();
|
||||
emit stateChanged();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
59
linphone-app/src/components/recorder/RecorderModel.hpp
Normal file
59
linphone-app/src/components/recorder/RecorderModel.hpp
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Copyright (c) 2021 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of linphone-desktop
|
||||
* (see https://www.linphone.org).
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef RECORDER_MODEL_H
|
||||
#define RECORDER_MODEL_H
|
||||
|
||||
#include "utils/LinphoneEnums.hpp"
|
||||
|
||||
// =============================================================================
|
||||
|
||||
|
||||
class RecorderModel : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
static std::shared_ptr<RecorderModel> create(std::shared_ptr<linphone::Recorder> recorder,QObject * parent = nullptr);// Call it instead constructor
|
||||
RecorderModel (std::shared_ptr<linphone::Recorder> recorder,QObject * parent = nullptr);
|
||||
virtual ~RecorderModel();
|
||||
|
||||
Q_PROPERTY(LinphoneEnums::RecorderState state READ getState NOTIFY stateChanged)
|
||||
Q_PROPERTY(QString file READ getFile NOTIFY fileChanged)
|
||||
|
||||
std::shared_ptr<linphone::Recorder> getRecorder();
|
||||
|
||||
Q_INVOKABLE int getDuration()const;
|
||||
LinphoneEnums::RecorderState getState() const;
|
||||
Q_INVOKABLE QString getFile()const;
|
||||
|
||||
Q_INVOKABLE void start();
|
||||
Q_INVOKABLE void pause();
|
||||
Q_INVOKABLE void stop();
|
||||
|
||||
signals:
|
||||
void stateChanged();
|
||||
void fileChanged();
|
||||
|
||||
private:
|
||||
std::shared_ptr<linphone::Recorder> mRecorder;
|
||||
};
|
||||
Q_DECLARE_METATYPE(std::shared_ptr<RecorderModel>)
|
||||
Q_DECLARE_METATYPE(RecorderModel*)
|
||||
#endif
|
||||
|
|
@ -37,11 +37,11 @@ namespace linphone {
|
|||
class SoundPlayer : public QObject {
|
||||
class Handlers;
|
||||
|
||||
Q_OBJECT;
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QString source READ getSource WRITE setSource NOTIFY sourceChanged);
|
||||
Q_PROPERTY(PlaybackState playbackState READ getPlaybackState WRITE setPlaybackState NOTIFY playbackStateChanged);
|
||||
Q_PROPERTY(int duration READ getDuration NOTIFY sourceChanged);
|
||||
Q_PROPERTY(QString source READ getSource WRITE setSource NOTIFY sourceChanged)
|
||||
Q_PROPERTY(PlaybackState playbackState READ getPlaybackState WRITE setPlaybackState NOTIFY playbackStateChanged)
|
||||
Q_PROPERTY(int duration READ getDuration NOTIFY sourceChanged)
|
||||
|
||||
public:
|
||||
enum PlaybackState {
|
||||
|
|
|
|||
|
|
@ -29,9 +29,11 @@ void LinphoneEnums::registerMetaTypes(){
|
|||
qRegisterMetaType<LinphoneEnums::FriendCapability>();
|
||||
qRegisterMetaType<LinphoneEnums::EventLogType>();
|
||||
qRegisterMetaType<LinphoneEnums::ChatMessageState>();
|
||||
qRegisterMetaType<LinphoneEnums::CallStatus>();
|
||||
qRegisterMetaType<LinphoneEnums::TunnelMode>();
|
||||
qRegisterMetaType<LinphoneEnums::RecorderState>();
|
||||
}
|
||||
|
||||
|
||||
linphone::MediaEncryption LinphoneEnums::toLinphone(const LinphoneEnums::MediaEncryption& data){
|
||||
return static_cast<linphone::MediaEncryption>(data);
|
||||
}
|
||||
|
|
@ -73,3 +75,10 @@ linphone::Tunnel::Mode LinphoneEnums::toLinphone(const LinphoneEnums::TunnelMode
|
|||
LinphoneEnums::TunnelMode LinphoneEnums::fromLinphone(const linphone::Tunnel::Mode& data){
|
||||
return static_cast<LinphoneEnums::TunnelMode>(data);
|
||||
}
|
||||
|
||||
linphone::RecorderState LinphoneEnums::toLinphone(const LinphoneEnums::RecorderState& data){
|
||||
return static_cast<linphone::RecorderState>(data);
|
||||
}
|
||||
LinphoneEnums::RecorderState LinphoneEnums::fromLinphone(const linphone::RecorderState& data){
|
||||
return static_cast<LinphoneEnums::RecorderState>(data);
|
||||
}
|
||||
|
|
@ -121,6 +121,16 @@ Q_ENUM_NS(TunnelMode)
|
|||
|
||||
linphone::Tunnel::Mode toLinphone(const LinphoneEnums::TunnelMode& mode);
|
||||
LinphoneEnums::TunnelMode fromLinphone(const linphone::Tunnel::Mode& mode);
|
||||
|
||||
enum RecorderState{
|
||||
RecorderStateClosed = int(linphone::RecorderState::Closed),
|
||||
RecorderStatePaused = int(linphone::RecorderState::Paused),
|
||||
RecorderStateRunning = int(linphone::RecorderState::Running)
|
||||
};
|
||||
Q_ENUM_NS(RecorderState)
|
||||
|
||||
linphone::RecorderState toLinphone(const LinphoneEnums::RecorderState& state);
|
||||
LinphoneEnums::RecorderState fromLinphone(const linphone::RecorderState& state);
|
||||
}
|
||||
|
||||
Q_DECLARE_METATYPE(LinphoneEnums::MediaEncryption)
|
||||
|
|
@ -129,5 +139,6 @@ Q_DECLARE_METATYPE(LinphoneEnums::EventLogType)
|
|||
Q_DECLARE_METATYPE(LinphoneEnums::ChatMessageState)
|
||||
Q_DECLARE_METATYPE(LinphoneEnums::CallStatus)
|
||||
Q_DECLARE_METATYPE(LinphoneEnums::TunnelMode)
|
||||
Q_DECLARE_METATYPE(LinphoneEnums::RecorderState)
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import QtQuick 2.7
|
||||
import QtQuick.Controls 2.2
|
||||
import QtQuick.Layouts 1.3
|
||||
import QtGraphicalEffects 1.12
|
||||
|
||||
import Common 1.0
|
||||
|
|
@ -33,6 +34,8 @@ Item {
|
|||
property bool useStates: true
|
||||
//property bool autoIcon : false // hovered/pressed : use an automatic layer instead of specific icon image
|
||||
property int iconSize : colorSet.iconSize
|
||||
property int iconHeight: colorSet.iconHeight ? colorSet.iconHeight : 0
|
||||
property int iconWidth: colorSet.iconWidth ? colorSet.iconWidth : 0
|
||||
readonly property alias hovered: button.hovered
|
||||
property alias text: button.text
|
||||
// Tooltip aliases
|
||||
|
|
@ -44,24 +47,34 @@ Item {
|
|||
|
||||
property alias backgroundRadius : backgroundColor.radius
|
||||
|
||||
property alias horizontalAlignment: icon.horizontalAlignment
|
||||
property alias verticalAlignment: icon.verticalAlignment
|
||||
property alias fillMode: icon.fillMode
|
||||
|
||||
// AutoColor for hide part alpha /4
|
||||
property color foregroundHiddenPartNormalColor : colorSet.foregroundNormalColor ? Qt.rgba(colorSet.foregroundNormalColor.r, colorSet.foregroundNormalColor.g, colorSet.foregroundNormalColor.b, colorSet.foregroundNormalColor.a/4) : 'transparent'
|
||||
property color foregroundHiddenPartDisabledColor : colorSet.foregroundDisabledColor ? Qt.rgba(colorSet.foregroundDisabledColor.r, colorSet.foregroundDisabledColor.g, colorSet.foregroundDisabledColor.b, colorSet.foregroundDisabledColor.a/4): 'transparent'
|
||||
property color foregroundHiddenPartHoveredColor : colorSet.foregroundHoveredColor ? Qt.rgba(colorSet.foregroundHoveredColor.r, colorSet.foregroundHoveredColor.g, colorSet.foregroundHoveredColor.b, colorSet.foregroundHoveredColor.a/4): 'transparent'
|
||||
property color foregroundHiddenPartUpdatingColor : colorSet.foregroundUpdatingColor ? Qt.rgba(colorSet.foregroundUpdatingColor.r, colorSet.foregroundUpdatingColor.g, colorSet.foregroundUpdatingColor.b, colorSet.foregroundUpdatingColor.a/4): 'transparent'
|
||||
property color foregroundHiddenPartPressedColor : colorSet.foregroundPressedColor ? Qt.rgba(colorSet.foregroundPressedColor.r, colorSet.foregroundPressedColor.g, colorSet.foregroundPressedColor.b, colorSet.foregroundPressedColor.a/4): 'transparent'
|
||||
|
||||
// Hidden part : transparent if not specified
|
||||
property color backgroundHiddenPartNormalColor : colorSet.backgroundHiddenPartNormalColor ? colorSet.backgroundHiddenPartNormalColor : (colorSet.backgroundNormalColor ? colorSet.backgroundNormalColor : 'transparent')
|
||||
property color backgroundHiddenPartDisabledColor : colorSet.backgroundHiddenPartDisabledColor ? colorSet.backgroundHiddenPartDisabledColor : (colorSet.backgroundDisabledColor ? colorSet.backgroundDisabledColor : 'transparent')
|
||||
property color backgroundHiddenPartHoveredColor : colorSet.backgroundHiddenPartHoveredColor ? colorSet.backgroundHiddenPartHoveredColor : (colorSet.backgroundHoveredColor ? colorSet.backgroundHoveredColor : 'transparent')
|
||||
property color backgroundHiddenPartUpdatingColor : colorSet.backgroundHiddenPartUpdatingColor ? colorSet.backgroundHiddenPartUpdatingColor : (colorSet.backgroundUpdatingColor ? colorSet.backgroundUpdatingColor : 'transparent')
|
||||
property color backgroundHiddenPartPressedColor : colorSet.backgroundHiddenPartPressedColor ? colorSet.backgroundHiddenPartPressedColor : (colorSet.backgroundPressedColor ? colorSet.backgroundPressedColor : 'transparent')
|
||||
|
||||
// AutoColor : alpha /4 for foreground
|
||||
property color foregroundHiddenPartNormalColor : colorSet.foregroundHiddenPartNormalColor ? colorSet.foregroundHiddenPartNormalColor : (colorSet.foregroundNormalColor ? Qt.rgba(colorSet.foregroundNormalColor.r, colorSet.foregroundNormalColor.g, colorSet.foregroundNormalColor.b, colorSet.foregroundNormalColor.a/4) : 'transparent')
|
||||
property color foregroundHiddenPartDisabledColor : colorSet.foregroundHiddenPartDisabledColor ? colorSet.foregroundHiddenPartDisabledColor : (colorSet.foregroundDisabledColor ? Qt.rgba(colorSet.foregroundDisabledColor.r, colorSet.foregroundDisabledColor.g, colorSet.foregroundDisabledColor.b, colorSet.foregroundDisabledColor.a/4): 'transparent')
|
||||
property color foregroundHiddenPartHoveredColor : colorSet.foregroundHiddenPartHoveredColor ? colorSet.foregroundHiddenPartHoveredColor : (colorSet.foregroundHoveredColor ? Qt.rgba(colorSet.foregroundHoveredColor.r, colorSet.foregroundHoveredColor.g, colorSet.foregroundHoveredColor.b, colorSet.foregroundHoveredColor.a/4): 'transparent')
|
||||
property color foregroundHiddenPartUpdatingColor : colorSet.foregroundHiddenPartUpdatingColor ? colorSet.foregroundHiddenPartUpdatingColor : (colorSet.foregroundUpdatingColor ? Qt.rgba(colorSet.foregroundUpdatingColor.r, colorSet.foregroundUpdatingColor.g, colorSet.foregroundUpdatingColor.b, colorSet.foregroundUpdatingColor.a/4): 'transparent')
|
||||
property color foregroundHiddenPartPressedColor : colorSet.foregroundHiddenPartPressedColor ? colorSet.foregroundHiddenPartPressedColor : (colorSet.foregroundPressedColor ? Qt.rgba(colorSet.foregroundPressedColor.r, colorSet.foregroundPressedColor.g, colorSet.foregroundPressedColor.b, colorSet.foregroundPressedColor.a/4): 'transparent')
|
||||
//---------------------------------------------
|
||||
property int percentageDisplayed : 100
|
||||
|
||||
|
||||
// If `useStates` = true, the used icons are:
|
||||
// `icon`_pressed, `icon`_hovered and `icon`_normal.
|
||||
property string icon : colorSet.icon
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
signal clicked
|
||||
signal clicked(real x, real y)
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
|
|
@ -120,6 +133,21 @@ Item {
|
|||
}else
|
||||
return "black"
|
||||
}
|
||||
function getBackgroundHiddenPartColor(){
|
||||
if(isCustom){
|
||||
if(wrappedButton.icon == '')
|
||||
return wrappedButton.backgroundHiddenPartNormalColor
|
||||
if (wrappedButton.updating)
|
||||
return wrappedButton.backgroundHiddenPartUpdatingColor
|
||||
if (!useStates)
|
||||
return wrappedButton.backgroundHiddenPartNormalColor
|
||||
if (!wrappedButton.enabled)
|
||||
return wrappedButton.backgroundHiddenPartDisabledColor
|
||||
return button.down ? wrappedButton.backgroundHiddenPartPressedColor
|
||||
: (button.hovered ? wrappedButton.backgroundHiddenPartHoveredColor: wrappedButton.backgroundHiddenPartNormalColor)
|
||||
}else
|
||||
return 'transparent'
|
||||
}
|
||||
function getForegroundHiddenPartColor(){
|
||||
if(isCustom){
|
||||
if(wrappedButton.icon == '')
|
||||
|
|
@ -137,20 +165,31 @@ Item {
|
|||
}
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
height: iconSize || parent.iconSize || parent.height
|
||||
width: iconSize || parent.iconSize || parent.width
|
||||
height: iconHeight || iconSize || parent.iconSize || parent.height
|
||||
width: iconWidth || iconSize || parent.iconSize || parent.width
|
||||
|
||||
Button {
|
||||
id: button
|
||||
|
||||
anchors.fill: parent
|
||||
background: Rectangle {
|
||||
id: backgroundColor
|
||||
color: getBackgroundColor()
|
||||
}
|
||||
background: Row{
|
||||
anchors.fill: parent
|
||||
Rectangle {
|
||||
height: parent.height
|
||||
width:parent.width * wrappedButton.percentageDisplayed / 100
|
||||
id: backgroundColor
|
||||
color: getBackgroundColor()
|
||||
}
|
||||
Rectangle {
|
||||
height: parent.height
|
||||
width: parent.width * ( 1 - wrappedButton.percentageDisplayed / 100 )
|
||||
id: backgroundHiddenPartColor
|
||||
color: getBackgroundHiddenPartColor()
|
||||
}
|
||||
}
|
||||
hoverEnabled: !wrappedButton.updating//|| wrappedButton.autoIcon
|
||||
|
||||
onClicked: !wrappedButton.updating && wrappedButton.enabled && wrappedButton.clicked()
|
||||
onClicked: !wrappedButton.updating && wrappedButton.enabled && wrappedButton.clicked(pressX, pressY)
|
||||
Rectangle{
|
||||
id: foregroundColor
|
||||
anchors.fill:parent
|
||||
|
|
@ -179,6 +218,7 @@ Item {
|
|||
id: icon
|
||||
|
||||
anchors.centerIn: parent
|
||||
anchors.fill: iconHeight>0 || iconWidth ? parent : undefined
|
||||
icon: {
|
||||
if(!Images[_getIcon()])
|
||||
console.log("No images for: "+_getIcon())
|
||||
|
|
@ -187,6 +227,8 @@ Item {
|
|||
iconSize: wrappedButton.iconSize || (
|
||||
parent.width > parent.height ? parent.height : parent.width
|
||||
)
|
||||
iconHeight: wrappedButton.iconHeight
|
||||
iconWidth: wrappedButton.iconWidth
|
||||
visible: !isCustom
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import QtQuick.Dialogs 1.2
|
|||
import QtQuick.Layouts 1.12
|
||||
|
||||
import Common 1.0
|
||||
import Linphone 1.0
|
||||
import Common.Styles 1.0
|
||||
import Utils 1.0
|
||||
|
||||
|
|
@ -30,6 +31,7 @@ Item {
|
|||
|
||||
signal dropped (var files)
|
||||
signal validText (string text)
|
||||
signal audioRecordRequest()
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
|
|
@ -86,7 +88,7 @@ Item {
|
|||
}
|
||||
// Record audio
|
||||
ActionButton {
|
||||
visible:false && droppableTextArea.enabled// TODO
|
||||
visible:droppableTextArea.enabled
|
||||
id: recordAudioButton
|
||||
|
||||
//anchors.verticalCenter: parent.verticalCenter
|
||||
|
|
@ -97,9 +99,7 @@ Item {
|
|||
backgroundRadius: 8
|
||||
colorSet: DroppableTextAreaStyle.chatMicro
|
||||
|
||||
useStates:false
|
||||
|
||||
onClicked: {console.log('Record audio request')}
|
||||
onClicked: droppableTextArea.audioRecordRequest()
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -137,7 +137,7 @@ Item {
|
|||
}
|
||||
}
|
||||
function handleValidation () {
|
||||
if (text.length !== 0) {
|
||||
if (RecorderManager.haveVocalRecorder || text.length !== 0) {
|
||||
validText(text)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,40 +12,40 @@ import Utils 1.0
|
|||
Item {
|
||||
id: mainItem
|
||||
property var iconSize // Required.
|
||||
property int iconHeight: 0 // Or this
|
||||
property int iconWidth: 0 // <-- too
|
||||
|
||||
property string icon
|
||||
property color overwriteColor
|
||||
property alias horizontalAlignment: image.horizontalAlignment
|
||||
property alias verticalAlignment: image.verticalAlignment
|
||||
property alias fillMode: image.fillMode
|
||||
|
||||
|
||||
// Use this slot because of testing overwriteColor in layer doesn't seem to work
|
||||
onOverwriteColorChanged: if(overwriteColor)
|
||||
image.colorOverwriteEnabled = true
|
||||
else
|
||||
image.colorOverwriteEnabled = false
|
||||
height: iconSize
|
||||
width: iconSize
|
||||
height: iconHeight > 0 ? iconHeight : iconSize
|
||||
width: iconWidth > 0 ? iconWidth : iconSize
|
||||
|
||||
Image {
|
||||
id:image
|
||||
property bool colorOverwriteEnabled : false
|
||||
mipmap: SettingsModel.mipmapEnabled
|
||||
cache: Images.areReadOnlyImages
|
||||
function getIconSize () {
|
||||
Utils.assert(
|
||||
(icon == null || icon == '' || iconSize != null && iconSize >= 0),
|
||||
'`iconSize` must be defined and must be positive. (icon=`' +
|
||||
icon + '`, iconSize=' + iconSize + ')'
|
||||
)
|
||||
|
||||
return iconSize
|
||||
}
|
||||
cache: Images.areReadOnlyImages
|
||||
|
||||
anchors.centerIn: parent
|
||||
//anchors.centerIn: parent
|
||||
anchors.fill: parent
|
||||
|
||||
width: iconSize
|
||||
height: iconSize
|
||||
//width: iconWidth > 0 ? iconWidth : mainItem.width
|
||||
//height: iconHeight > 0 ? iconHeight : mainItem.height
|
||||
|
||||
fillMode: Image.PreserveAspectFit
|
||||
source: Utils.resolveImageUri(icon)
|
||||
sourceSize.width: getIconSize()
|
||||
sourceSize.height: getIconSize()
|
||||
sourceSize.width: iconWidth > 0 ? iconWidth : iconSize
|
||||
sourceSize.height: iconHeight > 0 ? iconHeight : iconSize
|
||||
layer {
|
||||
enabled: image.colorOverwriteEnabled
|
||||
effect: ColorOverlay {
|
||||
|
|
|
|||
107
linphone-app/ui/modules/Common/Indicators/MediaProgressBar.qml
Normal file
107
linphone-app/ui/modules/Common/Indicators/MediaProgressBar.qml
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
import QtQuick 2.7
|
||||
import QtQuick.Controls 2.2
|
||||
import QtQuick.Layouts 1.3
|
||||
import QtGraphicalEffects 1.12
|
||||
|
||||
import Common 1.0
|
||||
import Linphone 1.0
|
||||
import Utils 1.0
|
||||
import Units 1.0
|
||||
import Common.Styles 1.0
|
||||
|
||||
// =============================================================================
|
||||
|
||||
ProgressBar {
|
||||
id: progressBar
|
||||
|
||||
property bool stopAtEnd: true
|
||||
property bool resetAtEnd: false
|
||||
property int progressDuration // Max duration
|
||||
property int progressPosition // Position of pregress bar in [0 ; progressDuration]
|
||||
property alias colorSet: progression.colorSet
|
||||
|
||||
function start(){
|
||||
progressBar.value = 0
|
||||
animationTest.start()
|
||||
}
|
||||
function resume(){
|
||||
if(progressBar.value >= 100)
|
||||
progressBar.value = 0
|
||||
animationTest.start()
|
||||
}
|
||||
function stop(){
|
||||
animationTest.stop()
|
||||
}
|
||||
signal endReached()
|
||||
signal refreshPositionRequested()
|
||||
signal seekRequested(int ms)
|
||||
Timer{
|
||||
id: animationTest
|
||||
repeat: true
|
||||
onTriggered: progressBar.refreshPositionRequested()
|
||||
interval: 5
|
||||
}
|
||||
to: 101
|
||||
value: 0
|
||||
onValueChanged:{
|
||||
if(value > 100){
|
||||
if( progressBar.stopAtEnd)
|
||||
stop()
|
||||
if(progressBar.resetAtEnd) {
|
||||
progressBar.value = 0
|
||||
progressPosition = 0
|
||||
}else{
|
||||
progressBar.value = 100// Stay at 100
|
||||
progressPosition = progressDuration
|
||||
}
|
||||
|
||||
progressBar.endReached()
|
||||
}else
|
||||
progression.percentageDisplayed = value
|
||||
}
|
||||
|
||||
anchors.topMargin: 5
|
||||
anchors.bottomMargin: 5
|
||||
|
||||
background: Rectangle {
|
||||
color: MediaProgressBarStyle.backgroundColor
|
||||
radius: 5
|
||||
}
|
||||
|
||||
|
||||
contentItem:
|
||||
Rectangle{
|
||||
anchors.fill: parent
|
||||
radius: 5
|
||||
RowLayout{
|
||||
anchors.fill: parent
|
||||
|
||||
ActionButton{
|
||||
id: progression
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
Layout.topMargin: 5
|
||||
Layout.bottomMargin: 5
|
||||
Layout.leftMargin: 10
|
||||
backgroundRadius: 5
|
||||
fillMode: Image.TileHorizontally
|
||||
verticalAlignment: Image.AlignLeft
|
||||
isCustom: true
|
||||
colorSet: MediaProgressBarStyle.progressionWave
|
||||
percentageDisplayed: 0
|
||||
onClicked: progressBar.seekRequested(x * progressBar.progressDuration/width)
|
||||
}
|
||||
Text{
|
||||
Layout.fillHeight: true
|
||||
Layout.preferredWidth: 100
|
||||
Layout.rightMargin: 10
|
||||
horizontalAlignment: Qt.AlignRight
|
||||
verticalAlignment: Qt.AlignVCenter
|
||||
text: progressBar.progressPosition >= 0 ? Utils.formatElapsedTime( progressBar.progressPosition / 1000 ) : '-'
|
||||
property font customFont : SettingsModel.textMessageFont
|
||||
font.family: customFont.family
|
||||
font.pointSize: Units.dp * (customFont.pointSize + 2)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
pragma Singleton
|
||||
import QtQml 2.2
|
||||
|
||||
import ColorsList 1.0
|
||||
|
||||
// =============================================================================
|
||||
|
||||
QtObject {
|
||||
property string sectionName: 'MediaProgressBar'
|
||||
|
||||
property color backgroundColor: ColorsList.add(sectionName+'_bg', 'k').color
|
||||
property string gaugeIcon: 'chat_audio_soundwave_custom'
|
||||
|
||||
property QtObject progressionWave: QtObject{
|
||||
property int iconSize: 30
|
||||
property int iconHeight: 40
|
||||
property int iconWidth: 250
|
||||
property string name : 'progression_soundwave'
|
||||
property string icon : 'chat_audio_soundwave_custom'
|
||||
property color backgroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_n', icon, 'a_n_b_bg').color
|
||||
property color backgroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_h', icon, 'a_h_b_bg').color
|
||||
property color backgroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_p', icon, 'a_p_b_bg').color
|
||||
property color foregroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_n', icon, 'a_n_b_fg').color
|
||||
property color foregroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_h', icon, 'a_h_b_fg').color
|
||||
property color foregroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_p', icon, 'a_p_b_fg').color
|
||||
|
||||
property color backgroundHiddenPartNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_hidden_bg_n', icon, 'l_n_b_bg').color
|
||||
property color backgroundHiddenPartHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_hidden_bg_h', icon, 'l_h_b_bg').color
|
||||
property color backgroundHiddenPartPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_hidden_bg_p', icon, 'l_p_b_bg').color
|
||||
|
||||
property color foregroundHiddenPartNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_hidden_fg_n', icon, 'l_n_b_fg').color
|
||||
property color foregroundHiddenPartHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_hidden_fg_h', icon, 'l_h_b_fg').color
|
||||
property color foregroundHiddenPartPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_hidden_fg_p', icon, 'l_p_b_fg').color
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -41,6 +41,7 @@ singleton FormVGroupStyle 1.0 Form/Placements/FormVGroupStyle.qml
|
|||
singleton TabButtonStyle 1.0 Form/Tab/TabButtonStyle.qml
|
||||
singleton TabContainerStyle 1.0 Form/Tab/TabContainerStyle.qml
|
||||
|
||||
singleton MediaProgressBarStyle 1.0 Indicators/MediaProgressBarStyle.qml
|
||||
singleton VuMeterStyle 1.0 Indicators/VuMeterStyle.qml
|
||||
|
||||
singleton ApplicationMenuStyle 1.0 Menus/ApplicationMenuStyle.qml
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@ InvertedMouseArea 1.0 Helpers/InvertedMouseArea.qml
|
|||
Icon 1.0 Image/Icon.qml
|
||||
RoundedImage 1.0 Image/RoundedImage.qml
|
||||
|
||||
MediaProgressBar 1.0 Indicators/MediaProgressBar.qml
|
||||
VuMeter 1.0 Indicators/VuMeter.qml
|
||||
|
||||
ApplicationMenu 1.0 Menus/ApplicationMenu.qml
|
||||
|
|
|
|||
|
|
@ -426,6 +426,7 @@ Rectangle {
|
|||
chatMessagePreview.hide()
|
||||
}
|
||||
}
|
||||
onAudioRecordRequest: RecorderManager.resetVocalRecorder()
|
||||
Component.onCompleted: {text = proxyModel.cachedText; cursorPosition=text.length}
|
||||
Rectangle{
|
||||
anchors.fill:parent
|
||||
|
|
|
|||
155
linphone-app/ui/modules/Linphone/Chat/ChatAudioPreview.qml
Normal file
155
linphone-app/ui/modules/Linphone/Chat/ChatAudioPreview.qml
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
import QtQuick 2.7
|
||||
import QtQuick.Controls 2.2
|
||||
import QtQuick.Layouts 1.3
|
||||
|
||||
import Common 1.0
|
||||
import Linphone 1.0
|
||||
import Linphone.Styles 1.0
|
||||
import Utils 1.0
|
||||
import UtilsCpp 1.0
|
||||
import LinphoneEnums 1.0
|
||||
|
||||
import Units 1.0
|
||||
|
||||
import 'Chat.js' as Logic
|
||||
|
||||
// =============================================================================
|
||||
|
||||
Rectangle{
|
||||
id: audioPreviewBlock
|
||||
property bool haveRecorder: RecorderManager.haveVocalRecorder
|
||||
property RecorderModel vocalRecorder : (haveRecorder ? RecorderManager.getVocalRecorder() : null)
|
||||
property bool isRecording : (vocalRecorder ? vocalRecorder.state != LinphoneEnums.RecorderStateClosed : false)
|
||||
property bool isPlaying : vocalPlayer.item && vocalPlayer.item.playbackState === SoundPlayer.PlayingState
|
||||
|
||||
onVocalRecorderChanged: if(haveRecorder)
|
||||
audioPreviewBlock.state = 'showed'
|
||||
onIsRecordingChanged: if(isRecording) {
|
||||
mediaProgressBar.start()
|
||||
}else
|
||||
mediaProgressBar.stop()
|
||||
onIsPlayingChanged: isPlaying ? mediaProgressBar.resume() : mediaProgressBar.stop()
|
||||
|
||||
Layout.preferredHeight: 70
|
||||
|
||||
color: ChatAudioPreviewStyle.backgroundColor
|
||||
radius: 0
|
||||
state: "hidden"
|
||||
visible: haveRecorder
|
||||
onVisibleChanged: if(!visible) hide()
|
||||
clip: false
|
||||
function hide(){
|
||||
state = 'hidden'
|
||||
}
|
||||
Loader {
|
||||
id: vocalPlayer
|
||||
|
||||
active: false
|
||||
sourceComponent: SoundPlayer {
|
||||
source: (haveRecorder && vocalRecorder? vocalRecorder.file : '')
|
||||
onStopped:{
|
||||
mediaProgressBar.value = 100
|
||||
}
|
||||
Component.onCompleted: {
|
||||
play()// This will open the file and allow seeking
|
||||
pause()
|
||||
}
|
||||
}
|
||||
}
|
||||
RowLayout{
|
||||
id: lineLayout
|
||||
anchors.fill: parent
|
||||
spacing: 10
|
||||
ActionButton{
|
||||
Layout.preferredHeight: iconSize
|
||||
Layout.preferredWidth: iconSize
|
||||
Layout.leftMargin: 10
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
isCustom: true
|
||||
colorSet: ChatAudioPreviewStyle.deleteAction
|
||||
onClicked: audioPreviewBlock.hide()
|
||||
}
|
||||
Item{
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
Layout.topMargin: 5
|
||||
Layout.bottomMargin: 5
|
||||
MediaProgressBar{
|
||||
id: mediaProgressBar
|
||||
anchors.fill: parent
|
||||
progressDuration: 0
|
||||
progressPosition: 0
|
||||
stopAtEnd: !audioPreviewBlock.isRecording
|
||||
resetAtEnd: false
|
||||
colorSet: isRecording ? ChatAudioPreviewStyle.recordingProgressionWave : ChatAudioPreviewStyle.progressionWave
|
||||
onEndReached:{
|
||||
if(vocalPlayer.item)
|
||||
vocalPlayer.item.stop()
|
||||
}
|
||||
onRefreshPositionRequested: if( vocalPlayer.item){
|
||||
progressPosition = vocalPlayer.item.getPosition()
|
||||
value = 100 * ( progressPosition / vocalPlayer.item.duration)
|
||||
}else{// Recording
|
||||
progressDuration = vocalRecorder.getDuration()
|
||||
progressPosition = progressDuration
|
||||
value = value + 0.01
|
||||
}
|
||||
onSeekRequested: if( vocalPlayer.item){
|
||||
vocalPlayer.item.seek(ms)
|
||||
progressPosition = vocalPlayer.item.getPosition()
|
||||
value = 100 * (progressPosition / vocalPlayer.item.duration)
|
||||
}
|
||||
}
|
||||
}
|
||||
ActionButton{
|
||||
Layout.preferredHeight: iconSize
|
||||
Layout.preferredWidth: iconSize
|
||||
Layout.rightMargin: 15
|
||||
Layout.leftMargin: 5
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
isCustom: true
|
||||
colorSet: audioPreviewBlock.isRecording ? ChatAudioPreviewStyle.stopAction
|
||||
: (audioPreviewBlock.isPlaying ? ChatAudioPreviewStyle.pauseAction
|
||||
: ChatAudioPreviewStyle.playAction)
|
||||
onClicked:{
|
||||
if(audioPreviewBlock.isRecording){// Stop the record and save the file
|
||||
audioPreviewBlock.vocalRecorder.stop()
|
||||
mediaProgressBar.value = 100
|
||||
vocalPlayer.active = true
|
||||
}else if(audioPreviewBlock.isPlaying){// Pause the play
|
||||
vocalPlayer.item.pause()
|
||||
}else{// Play the audio
|
||||
vocalPlayer.item.play()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
states: [
|
||||
State {
|
||||
name: "hidden"
|
||||
PropertyChanges { target: audioPreviewBlock; opacity: 0 }
|
||||
},
|
||||
State {
|
||||
name: "showed"
|
||||
PropertyChanges { target: audioPreviewBlock; opacity: 1 }
|
||||
}
|
||||
]
|
||||
transitions: [
|
||||
Transition {
|
||||
from: "*"; to: "showed"
|
||||
SequentialAnimation{
|
||||
ScriptAction{ script: audioPreviewBlock.vocalRecorder.start() }
|
||||
NumberAnimation{ properties: "opacity"; easing.type: Easing.OutBounce; duration: 250 }
|
||||
}
|
||||
},
|
||||
Transition {
|
||||
from: "*"; to: "hidden"
|
||||
SequentialAnimation{
|
||||
ScriptAction{ script: RecorderManager.clearVocalRecorder()}
|
||||
ScriptAction{ script: vocalPlayer.active = false }
|
||||
NumberAnimation{ properties: "opacity"; duration: 250 }
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -49,7 +49,7 @@ Item {
|
|||
id: headerText
|
||||
height: icon.height
|
||||
verticalAlignment: Qt.AlignVCenter
|
||||
property string forwardInfo: mainChatMessageModel.getForwardInfoDisplayName
|
||||
property string forwardInfo: mainChatMessageModel ? mainChatMessageModel.getForwardInfoDisplayName : ''
|
||||
//: 'Forwarded' : Header on a message that contains a forward.
|
||||
text: 'Forwarded' + (forwardInfo ? ' : ' +forwardInfo : '')
|
||||
font.family: mainItem.customFont.family
|
||||
|
|
|
|||
|
|
@ -15,18 +15,22 @@ import 'Chat.js' as Logic
|
|||
// =============================================================================
|
||||
ColumnLayout{
|
||||
property alias replyChatMessageModel : replyPreview.replyChatMessageModel
|
||||
property int maxHeight: parent.height
|
||||
property int maxHeight: parent.height - ( audioPreview.visible ? audioPreview.height : 0)
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
height: replyPreview.height
|
||||
spacing: 0
|
||||
|
||||
function hide(){
|
||||
replyPreview.hide()
|
||||
audioPreview.hide()
|
||||
}
|
||||
|
||||
ChatReplyPreview{
|
||||
id: replyPreview
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
ChatAudioPreview{
|
||||
id: audioPreview
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
|
|
@ -33,7 +33,7 @@ Item {
|
|||
|
||||
width: maxWidth < 0 || maxWidth > fitWidth ? fitWidth : maxWidth
|
||||
height: fitHeight
|
||||
onMainChatMessageModelChanged: if( mainChatMessageModel.replyChatMessageModel) chatMessageModel = mainChatMessageModel.replyChatMessageModel
|
||||
onMainChatMessageModelChanged: if( mainChatMessageModel && mainChatMessageModel.replyChatMessageModel) chatMessageModel = mainChatMessageModel.replyChatMessageModel
|
||||
|
||||
|
||||
ColumnLayout{
|
||||
|
|
@ -118,7 +118,7 @@ Item {
|
|||
font.pointSize: Units.dp * (customFont.pointSize + ChatReplyMessageStyle.replyArea.pointSizeOffset)
|
||||
font.weight: Font.Light
|
||||
color: ChatReplyMessageStyle.replyArea.foregroundColor
|
||||
text: (visible ? Utils.encodeTextToQmlRichFormat(chatMessageModel.content, {
|
||||
text: (visible && chatMessageModel? Utils.encodeTextToQmlRichFormat(chatMessageModel.content, {
|
||||
imagesHeight: ChatStyle.entry.message.images.height,
|
||||
imagesWidth: ChatStyle.entry.message.images.width
|
||||
})
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ Rectangle{
|
|||
property ChatMessageModel replyChatMessageModel
|
||||
onReplyChatMessageModelChanged: if(replyChatMessageModel) replyPreviewBlock.state = "showed"
|
||||
|
||||
Layout.preferredHeight: Math.min(replayPreviewText.implicitHeight + replyPreviewHeaderArea.implicitHeight + 10, parent.maxHeight)
|
||||
Layout.preferredHeight: Math.min(replyPreviewText.implicitHeight + replyPreviewHeaderArea.implicitHeight + 10, parent.maxHeight)
|
||||
|
||||
property int leftMargin: textArea.textLeftMargin
|
||||
property int rightMargin: textArea.textRightMargin
|
||||
|
|
@ -69,11 +69,11 @@ Rectangle{
|
|||
}
|
||||
}
|
||||
Flickable {
|
||||
id: replayPreviewTextArea
|
||||
ScrollBar.vertical: ForceScrollBar {visible: replayPreviewTextArea.height < replayPreviewText.implicitHeight}
|
||||
id: replyPreviewTextArea
|
||||
ScrollBar.vertical: ForceScrollBar {visible: replyPreviewTextArea.height < replyPreviewText.implicitHeight}
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
clip: true
|
||||
contentHeight: replayPreviewText.implicitHeight
|
||||
contentHeight: replyPreviewText.implicitHeight
|
||||
contentWidth: width - ScrollBar.vertical.width
|
||||
flickableDirection: Flickable.VerticalFlick
|
||||
|
||||
|
|
@ -81,7 +81,7 @@ Rectangle{
|
|||
Layout.fillWidth: true
|
||||
|
||||
TextEdit {
|
||||
id: replayPreviewText
|
||||
id: replyPreviewText
|
||||
property font customFont : SettingsModel.textMessageFont
|
||||
|
||||
anchors.left: parent.left
|
||||
|
|
|
|||
|
|
@ -0,0 +1,120 @@
|
|||
pragma Singleton
|
||||
import QtQml 2.2
|
||||
|
||||
import Units 1.0
|
||||
import ColorsList 1.0
|
||||
|
||||
// =============================================================================
|
||||
|
||||
QtObject {
|
||||
property string sectionName : 'ChatAudioPreview'
|
||||
property color color: ColorsList.add(sectionName, 'q').color
|
||||
property QtObject header: QtObject{
|
||||
property color color: ColorsList.add(sectionName+'_header', 'h').color
|
||||
property int pointSizeOffset: -3
|
||||
property QtObject replyIcon: QtObject{
|
||||
property string icon : 'menu_reply_custom'
|
||||
property int iconSize: 22
|
||||
}
|
||||
}
|
||||
property color backgroundColor: ColorsList.add(sectionName+'_bg', 'aa').color
|
||||
|
||||
property QtObject audioArea: QtObject{
|
||||
property color outgoingMarkColor: ColorsList.add(sectionName+'_reply_outgoing_mark', 'm').color
|
||||
property color incomingMarkColor: ColorsList.add(sectionName+'_reply_incoming_mark', 'r').color
|
||||
property color backgroundColor: ColorsList.add(sectionName+'_reply_bg', 'q').color
|
||||
property color foregroundColor: ColorsList.add(sectionName+'_reply_fg', 'h').color
|
||||
property int usernamePointSizeOffset: -2
|
||||
property int pointSizeOffset: -2
|
||||
}
|
||||
property QtObject deleteAction: QtObject {
|
||||
property int iconSize: 40
|
||||
property string name : 'delete'
|
||||
property string icon : 'delete_custom'
|
||||
property color backgroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_n', icon, 'me_n_b_bg').color
|
||||
property color backgroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_h', icon, 'me_h_b_bg').color
|
||||
property color backgroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_p', icon, 'me_p_b_bg').color
|
||||
property color foregroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_n', icon, 'me_n_b_fg').color
|
||||
property color foregroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_h', icon, 'me_h_b_fg').color
|
||||
property color foregroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_p', icon, 'me_p_b_fg').color
|
||||
}
|
||||
property QtObject stopAction: QtObject {
|
||||
property int iconSize: 30
|
||||
property string name : 'stop'
|
||||
property string icon : 'chat_audio_stop_custom'
|
||||
property color backgroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_n', icon, 'me_n_b_bg').color
|
||||
property color backgroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_h', icon, 'me_h_b_bg').color
|
||||
property color backgroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_p', icon, 'me_p_b_bg').color
|
||||
property color foregroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_n', icon, 'me_n_b_fg').color
|
||||
property color foregroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_h', icon, 'me_h_b_fg').color
|
||||
property color foregroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_p', icon, 'me_p_b_fg').color
|
||||
}
|
||||
property QtObject pauseAction: QtObject {
|
||||
property int iconSize: 30
|
||||
property string name : 'pause'
|
||||
property string icon : 'chat_audio_pause_custom'
|
||||
property color backgroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_n', icon, 'me_n_b_bg').color
|
||||
property color backgroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_h', icon, 'me_h_b_bg').color
|
||||
property color backgroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_p', icon, 'me_p_b_bg').color
|
||||
property color foregroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_n', icon, 'me_n_b_fg').color
|
||||
property color foregroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_h', icon, 'me_h_b_fg').color
|
||||
property color foregroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_p', icon, 'me_p_b_fg').color
|
||||
}
|
||||
property QtObject playAction: QtObject {
|
||||
property int iconSize: 30
|
||||
property string name : 'play'
|
||||
property string icon : 'chat_audio_play_custom'
|
||||
property color backgroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_n', icon, 'me_n_b_bg').color
|
||||
property color backgroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_h', icon, 'me_h_b_bg').color
|
||||
property color backgroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_p', icon, 'me_p_b_bg').color
|
||||
property color foregroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_n', icon, 'me_n_b_fg').color
|
||||
property color foregroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_h', icon, 'me_h_b_fg').color
|
||||
property color foregroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_p', icon, 'me_p_b_fg').color
|
||||
}
|
||||
|
||||
property QtObject progressionWave: QtObject{
|
||||
property int iconSize: 30
|
||||
property int iconHeight: 40
|
||||
property int iconWidth: 250
|
||||
property string name : 'progression_soundwave'
|
||||
property string icon : 'chat_audio_soundwave_custom'
|
||||
property color backgroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_n', icon, 'a_n_b_bg').color
|
||||
property color backgroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_h', icon, 'a_h_b_bg').color
|
||||
property color backgroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_p', icon, 'a_p_b_bg').color
|
||||
property color foregroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_n', icon, 'a_n_b_fg').color
|
||||
property color foregroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_h', icon, 'a_h_b_fg').color
|
||||
property color foregroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_p', icon, 'a_p_b_fg').color
|
||||
|
||||
property color backgroundHiddenPartNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_hidden_bg_n', icon, 'l_n_b_bg').color
|
||||
property color backgroundHiddenPartHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_hidden_bg_h', icon, 'l_h_b_bg').color
|
||||
property color backgroundHiddenPartPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_hidden_bg_p', icon, 'l_p_b_bg').color
|
||||
|
||||
property color foregroundHiddenPartNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_hidden_fg_n', icon, 'l_n_b_fg').color
|
||||
property color foregroundHiddenPartHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_hidden_fg_h', icon, 'l_h_b_fg').color
|
||||
property color foregroundHiddenPartPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_hidden_fg_p', icon, 'l_p_b_fg').color
|
||||
}
|
||||
|
||||
property QtObject recordingProgressionWave: QtObject{
|
||||
property int iconSize: 30
|
||||
property int iconHeight: 40
|
||||
property int iconWidth: 250
|
||||
property string name : 'recording_progression_soundwave'
|
||||
property string icon : 'chat_audio_soundwave_custom'
|
||||
property color backgroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_n', icon, 'r_n_b_bg').color
|
||||
property color backgroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_h', icon, 'r_h_b_bg').color
|
||||
property color backgroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_p', icon, 'r_p_b_bg').color
|
||||
property color foregroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_n', icon, 'r_n_b_fg').color
|
||||
property color foregroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_h', icon, 'r_h_b_fg').color
|
||||
property color foregroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_p', icon, 'r_p_b_fg').color
|
||||
|
||||
property color backgroundHiddenPartNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_hidden_bg_n', icon, 'l_n_b_bg').color
|
||||
property color backgroundHiddenPartHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_hidden_bg_h', icon, 'l_h_b_bg').color
|
||||
property color backgroundHiddenPartPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_hidden_bg_p', icon, 'l_p_b_bg').color
|
||||
|
||||
property color foregroundHiddenPartNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_hidden_fg_n', icon, 'l_n_b_fg').color
|
||||
property color foregroundHiddenPartHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_hidden_fg_h', icon, 'l_h_b_fg').color
|
||||
property color foregroundHiddenPartPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_hidden_fg_p', icon, 'l_p_b_fg').color
|
||||
}
|
||||
|
||||
property int padding: 8
|
||||
}
|
||||
|
|
@ -10,6 +10,7 @@ singleton CardBlockStyle 1.0 Blocks/CardBlockStyle.qml
|
|||
singleton RequestBlockStyle 1.0 Blocks/RequestBlockStyle.qml
|
||||
|
||||
singleton ChatStyle 1.0 Chat/ChatStyle.qml
|
||||
singleton ChatAudioPreviewStyle 1.0 Chat/ChatAudioPreviewStyle.qml
|
||||
singleton ChatForwardMessageStyle 1.0 Chat/ChatForwardMessageStyle.qml
|
||||
singleton ChatReplyMessageStyle 1.0 Chat/ChatReplyMessageStyle.qml
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ Calls 1.0 Calls/Calls.qml
|
|||
CallStatistics 1.0 Calls/CallStatistics.qml
|
||||
|
||||
Chat 1.0 Chat/Chat.qml
|
||||
ChatAudioPreview 1.0 Chat/ChatAudioPreview.qml
|
||||
ChatMessagePreview 1.0 Chat/ChatMessagePreview.qml
|
||||
ChatForwardMessage 1.0 Chat/ChatForwardMessage.qml
|
||||
ChatReplyMessage 1.0 Chat/ChatReplyMessage.qml
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 3ea9277c8035deb632e47519971122550ca8f64d
|
||||
Subproject commit b1171bf5faf08237ddc6e074b71dd6319c0470af
|
||||
Loading…
Add table
Reference in a new issue