diff --git a/CHANGELOG.md b/CHANGELOG.md
index f4bfa9b0d..81aec64b6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* Resizeable on mouse's wheel.
* Reset on mouse's right click (first for size if changed, second for position)
- Hide the active speaker from the mini views.
+- Display recordings list from the burger menu.
### Fixed
- Mini views layout on actives speaker.
diff --git a/linphone-app/CMakeLists.txt b/linphone-app/CMakeLists.txt
index b0231492a..9f6fe0d5a 100644
--- a/linphone-app/CMakeLists.txt
+++ b/linphone-app/CMakeLists.txt
@@ -212,6 +212,7 @@ set(SOURCES
src/components/core/event-count-notifier/AbstractEventCountNotifier.cpp
src/components/file/FileDownloader.cpp
src/components/file/FileExtractor.cpp
+ src/components/file/FileMediaModel.cpp
src/components/friend/FriendListListener.cpp
src/components/history/HistoryModel.cpp
src/components/history/HistoryProxyModel.cpp
@@ -246,6 +247,8 @@ set(SOURCES
src/components/presence/Presence.cpp
src/components/recorder/RecorderManager.cpp
src/components/recorder/RecorderModel.cpp
+ src/components/recorder/RecordingListModel.cpp
+ src/components/recorder/RecordingProxyModel.cpp
src/components/search/SearchListener.cpp
src/components/search/SearchResultModel.cpp
src/components/search/SearchSipAddressesModel.cpp
@@ -348,6 +351,7 @@ set(HEADERS
src/components/core/event-count-notifier/AbstractEventCountNotifier.hpp
src/components/file/FileDownloader.hpp
src/components/file/FileExtractor.hpp
+ src/components/file/FileMediaModel.hpp
src/components/friend/FriendListListener.hpp
src/components/history/HistoryModel.hpp
src/components/history/HistoryProxyModel.hpp
@@ -383,6 +387,8 @@ set(HEADERS
src/components/presence/Presence.hpp
src/components/recorder/RecorderManager.hpp
src/components/recorder/RecorderModel.hpp
+ src/components/recorder/RecordingListModel.hpp
+ src/components/recorder/RecordingProxyModel.hpp
src/components/search/SearchListener.hpp
src/components/search/SearchResultModel.hpp
src/components/search/SearchSipAddressesModel.hpp
diff --git a/linphone-app/assets/images/recordings_custom.svg b/linphone-app/assets/images/recordings_custom.svg
new file mode 100644
index 000000000..17be9e8df
--- /dev/null
+++ b/linphone-app/assets/images/recordings_custom.svg
@@ -0,0 +1,85 @@
+
+
diff --git a/linphone-app/assets/languages/da.ts b/linphone-app/assets/languages/da.ts
index ef140d3c4..b97fc3918 100644
--- a/linphone-app/assets/languages/da.ts
+++ b/linphone-app/assets/languages/da.ts
@@ -1792,6 +1792,11 @@ Klik her: <a href="%1">%1</a>
'Check for updates' : Item menu for checking updates
Tjek for opdateringer
+
+ recordings
+ 'Recordings' : Label for the recordings menu.
+
+
MainWindowTopMenuBar
@@ -1812,6 +1817,11 @@ Klik her: <a href="%1">%1</a>
'Check for updates' : Item menu for checking updates
Tjek for opdateringer
+
+ recordings
+ 'Recordings' : Label for the recordings menu.
+
+
ManageAccounts
@@ -2292,6 +2302,24 @@ Klik her: <a href="%1">%1</a>
+
+ Recordings
+
+ titleNoRecordings
+ 'No recordings' : Title of an empty list of records.
+
+
+
+ recordingsVocalLabel
+ 'Vocal' : Label for recording type that is a vocal message.
+
+
+
+ recordingsDelete
+ 'Are you sure you want to delete this item?' : Confirmation message for removing a record.
+
+
+
SettingsAdvanced
diff --git a/linphone-app/assets/languages/de.ts b/linphone-app/assets/languages/de.ts
index a1b2b06b7..a227f29d9 100644
--- a/linphone-app/assets/languages/de.ts
+++ b/linphone-app/assets/languages/de.ts
@@ -1792,6 +1792,11 @@ Klicken Sie hier: <a href="%1">%1</a>
'Check for updates' : Item menu for checking updates
Auf Aktualisierungen prüfen
+
+ recordings
+ 'Recordings' : Label for the recordings menu.
+
+
MainWindowTopMenuBar
@@ -1812,6 +1817,11 @@ Klicken Sie hier: <a href="%1">%1</a>
'Check for updates' : Item menu for checking updates
Auf Aktualisierungen prüfen
+
+ recordings
+ 'Recordings' : Label for the recordings menu.
+
+
ManageAccounts
@@ -2292,6 +2302,24 @@ Klicken Sie hier: <a href="%1">%1</a>
Automatisch
+
+ Recordings
+
+ titleNoRecordings
+ 'No recordings' : Title of an empty list of records.
+
+
+
+ recordingsVocalLabel
+ 'Vocal' : Label for recording type that is a vocal message.
+
+
+
+ recordingsDelete
+ 'Are you sure you want to delete this item?' : Confirmation message for removing a record.
+
+
+
SettingsAdvanced
diff --git a/linphone-app/assets/languages/en.ts b/linphone-app/assets/languages/en.ts
index 5f69dff3a..2b6e9ea7c 100644
--- a/linphone-app/assets/languages/en.ts
+++ b/linphone-app/assets/languages/en.ts
@@ -1792,6 +1792,11 @@ Click here: <a href="%1">%1</a>
'Check for updates' : Item menu for checking updates
Check for updates
+
+ recordings
+ 'Recordings' : Label for the recordings menu.
+ Recordings
+
MainWindowTopMenuBar
@@ -1812,6 +1817,11 @@ Click here: <a href="%1">%1</a>
'Check for updates' : Item menu for checking updates
Check for updates
+
+ recordings
+ 'Recordings' : Label for the recordings menu.
+ Recordings
+
ManageAccounts
@@ -2292,6 +2302,24 @@ Click here: <a href="%1">%1</a>
Auto
+
+ Recordings
+
+ titleNoRecordings
+ 'No recordings' : Title of an empty list of records.
+ No recordings
+
+
+ recordingsVocalLabel
+ 'Vocal' : Label for recording type that is a vocal message.
+ Vocal
+
+
+ recordingsDelete
+ 'Are you sure you want to delete this item?' : Confirmation message for removing a record.
+ Are you sure you want to delete this item?
+
+
SettingsAdvanced
diff --git a/linphone-app/assets/languages/es.ts b/linphone-app/assets/languages/es.ts
index 039bd89a1..fea36ac50 100644
--- a/linphone-app/assets/languages/es.ts
+++ b/linphone-app/assets/languages/es.ts
@@ -1792,6 +1792,11 @@ Haga clic aquí: <a href="%1">%1 </a>
'Check for updates' : Item menu for checking updates
Buscar actualizaciones
+
+ recordings
+ 'Recordings' : Label for the recordings menu.
+
+
MainWindowTopMenuBar
@@ -1812,6 +1817,11 @@ Haga clic aquí: <a href="%1">%1 </a>
'Check for updates' : Item menu for checking updates
Buscar actualizaciones
+
+ recordings
+ 'Recordings' : Label for the recordings menu.
+
+
ManageAccounts
@@ -2292,6 +2302,24 @@ Haga clic aquí: <a href="%1">%1 </a>
+
+ Recordings
+
+ titleNoRecordings
+ 'No recordings' : Title of an empty list of records.
+
+
+
+ recordingsVocalLabel
+ 'Vocal' : Label for recording type that is a vocal message.
+
+
+
+ recordingsDelete
+ 'Are you sure you want to delete this item?' : Confirmation message for removing a record.
+
+
+
SettingsAdvanced
diff --git a/linphone-app/assets/languages/fr_FR.ts b/linphone-app/assets/languages/fr_FR.ts
index 57547d66e..c800c0525 100644
--- a/linphone-app/assets/languages/fr_FR.ts
+++ b/linphone-app/assets/languages/fr_FR.ts
@@ -1792,6 +1792,11 @@ Cliquez ici : <a href="%1">%1</a>
'Check for updates' : Item menu for checking updates
Vérifier les mises à jour
+
+ recordings
+ 'Recordings' : Label for the recordings menu.
+
+
MainWindowTopMenuBar
@@ -1812,6 +1817,11 @@ Cliquez ici : <a href="%1">%1</a>
'Check for updates' : Item menu for checking updates
Vérifier les mises à jour
+
+ recordings
+ 'Recordings' : Label for the recordings menu.
+
+
ManageAccounts
@@ -2292,6 +2302,24 @@ Cliquez ici : <a href="%1">%1</a>
Auto
+
+ Recordings
+
+ titleNoRecordings
+ 'No recordings' : Title of an empty list of records.
+
+
+
+ recordingsVocalLabel
+ 'Vocal' : Label for recording type that is a vocal message.
+
+
+
+ recordingsDelete
+ 'Are you sure you want to delete this item?' : Confirmation message for removing a record.
+
+
+
SettingsAdvanced
diff --git a/linphone-app/assets/languages/hu.ts b/linphone-app/assets/languages/hu.ts
index ce392ee15..32e6d1c33 100644
--- a/linphone-app/assets/languages/hu.ts
+++ b/linphone-app/assets/languages/hu.ts
@@ -1782,6 +1782,11 @@ Kattintson ide: <a href="%1">%1</a>
'Check for updates' : Item menu for checking updates
Frissítések keresése
+
+ recordings
+ 'Recordings' : Label for the recordings menu.
+
+
MainWindowTopMenuBar
@@ -1802,6 +1807,11 @@ Kattintson ide: <a href="%1">%1</a>
'Check for updates' : Item menu for checking updates
Frissítések keresése
+
+ recordings
+ 'Recordings' : Label for the recordings menu.
+
+
ManageAccounts
@@ -2279,6 +2289,24 @@ Kattintson ide: <a href="%1">%1</a>
Önműködő
+
+ Recordings
+
+ titleNoRecordings
+ 'No recordings' : Title of an empty list of records.
+
+
+
+ recordingsVocalLabel
+ 'Vocal' : Label for recording type that is a vocal message.
+
+
+
+ recordingsDelete
+ 'Are you sure you want to delete this item?' : Confirmation message for removing a record.
+
+
+
SettingsAdvanced
diff --git a/linphone-app/assets/languages/it.ts b/linphone-app/assets/languages/it.ts
index c4d768163..5522db170 100644
--- a/linphone-app/assets/languages/it.ts
+++ b/linphone-app/assets/languages/it.ts
@@ -1792,6 +1792,11 @@ Clicca: <a href="%1">%1</a>
'Check for updates' : Item menu for checking updates
Controlla aggiornamenti
+
+ recordings
+ 'Recordings' : Label for the recordings menu.
+
+
MainWindowTopMenuBar
@@ -1812,6 +1817,11 @@ Clicca: <a href="%1">%1</a>
'Check for updates' : Item menu for checking updates
Controlla aggiornamenti
+
+ recordings
+ 'Recordings' : Label for the recordings menu.
+
+
ManageAccounts
@@ -2292,6 +2302,24 @@ Clicca: <a href="%1">%1</a>
Automatico
+
+ Recordings
+
+ titleNoRecordings
+ 'No recordings' : Title of an empty list of records.
+
+
+
+ recordingsVocalLabel
+ 'Vocal' : Label for recording type that is a vocal message.
+
+
+
+ recordingsDelete
+ 'Are you sure you want to delete this item?' : Confirmation message for removing a record.
+
+
+
SettingsAdvanced
diff --git a/linphone-app/assets/languages/ja.ts b/linphone-app/assets/languages/ja.ts
index 557a37a20..952b857d5 100644
--- a/linphone-app/assets/languages/ja.ts
+++ b/linphone-app/assets/languages/ja.ts
@@ -1782,6 +1782,11 @@
'Check for updates' : Item menu for checking updates
+
+ recordings
+ 'Recordings' : Label for the recordings menu.
+
+
MainWindowTopMenuBar
@@ -1802,6 +1807,11 @@
'Check for updates' : Item menu for checking updates
+
+ recordings
+ 'Recordings' : Label for the recordings menu.
+
+
ManageAccounts
@@ -2279,6 +2289,24 @@
+
+ Recordings
+
+ titleNoRecordings
+ 'No recordings' : Title of an empty list of records.
+
+
+
+ recordingsVocalLabel
+ 'Vocal' : Label for recording type that is a vocal message.
+
+
+
+ recordingsDelete
+ 'Are you sure you want to delete this item?' : Confirmation message for removing a record.
+
+
+
SettingsAdvanced
diff --git a/linphone-app/assets/languages/lt.ts b/linphone-app/assets/languages/lt.ts
index 29cb489f1..ade294354 100644
--- a/linphone-app/assets/languages/lt.ts
+++ b/linphone-app/assets/languages/lt.ts
@@ -1802,6 +1802,11 @@ Spustelėkite čia: <a href="%1">%1</a>
'Check for updates' : Item menu for checking updates
+
+ recordings
+ 'Recordings' : Label for the recordings menu.
+
+
MainWindowTopMenuBar
@@ -1822,6 +1827,11 @@ Spustelėkite čia: <a href="%1">%1</a>
'Check for updates' : Item menu for checking updates
+
+ recordings
+ 'Recordings' : Label for the recordings menu.
+
+
ManageAccounts
@@ -2305,6 +2315,24 @@ Spustelėkite čia: <a href="%1">%1</a>
+
+ Recordings
+
+ titleNoRecordings
+ 'No recordings' : Title of an empty list of records.
+
+
+
+ recordingsVocalLabel
+ 'Vocal' : Label for recording type that is a vocal message.
+
+
+
+ recordingsDelete
+ 'Are you sure you want to delete this item?' : Confirmation message for removing a record.
+
+
+
SettingsAdvanced
diff --git a/linphone-app/assets/languages/pt_BR.ts b/linphone-app/assets/languages/pt_BR.ts
index aaced721e..59c7cc682 100644
--- a/linphone-app/assets/languages/pt_BR.ts
+++ b/linphone-app/assets/languages/pt_BR.ts
@@ -1792,6 +1792,11 @@ Clique aqui: <a href="%1">%1 </a>
'Check for updates' : Item menu for checking updates
Verifique se há atualizações
+
+ recordings
+ 'Recordings' : Label for the recordings menu.
+
+
MainWindowTopMenuBar
@@ -1812,6 +1817,11 @@ Clique aqui: <a href="%1">%1 </a>
'Check for updates' : Item menu for checking updates
Verifique se há atualizações
+
+ recordings
+ 'Recordings' : Label for the recordings menu.
+
+
ManageAccounts
@@ -2292,6 +2302,24 @@ Clique aqui: <a href="%1">%1 </a>
Auto
+
+ Recordings
+
+ titleNoRecordings
+ 'No recordings' : Title of an empty list of records.
+
+
+
+ recordingsVocalLabel
+ 'Vocal' : Label for recording type that is a vocal message.
+
+
+
+ recordingsDelete
+ 'Are you sure you want to delete this item?' : Confirmation message for removing a record.
+
+
+
SettingsAdvanced
diff --git a/linphone-app/assets/languages/ru.ts b/linphone-app/assets/languages/ru.ts
index 770bd2d14..c5a1fc4f9 100644
--- a/linphone-app/assets/languages/ru.ts
+++ b/linphone-app/assets/languages/ru.ts
@@ -1802,6 +1802,11 @@
'Check for updates' : Item menu for checking updates
Проверить обновления
+
+ recordings
+ 'Recordings' : Label for the recordings menu.
+
+
MainWindowTopMenuBar
@@ -1822,6 +1827,11 @@
'Check for updates' : Item menu for checking updates
Проверить обновления
+
+ recordings
+ 'Recordings' : Label for the recordings menu.
+
+
ManageAccounts
@@ -2305,6 +2315,24 @@
Авто
+
+ Recordings
+
+ titleNoRecordings
+ 'No recordings' : Title of an empty list of records.
+
+
+
+ recordingsVocalLabel
+ 'Vocal' : Label for recording type that is a vocal message.
+
+
+
+ recordingsDelete
+ 'Are you sure you want to delete this item?' : Confirmation message for removing a record.
+
+
+
SettingsAdvanced
diff --git a/linphone-app/assets/languages/sv.ts b/linphone-app/assets/languages/sv.ts
index da6160940..29946ef18 100644
--- a/linphone-app/assets/languages/sv.ts
+++ b/linphone-app/assets/languages/sv.ts
@@ -1792,6 +1792,11 @@ Klicka här: <a href="%1">%1</a>
'Check for updates' : Item menu for checking updates
+
+ recordings
+ 'Recordings' : Label for the recordings menu.
+
+
MainWindowTopMenuBar
@@ -1812,6 +1817,11 @@ Klicka här: <a href="%1">%1</a>
'Check for updates' : Item menu for checking updates
+
+ recordings
+ 'Recordings' : Label for the recordings menu.
+
+
ManageAccounts
@@ -2292,6 +2302,24 @@ Klicka här: <a href="%1">%1</a>
+
+ Recordings
+
+ titleNoRecordings
+ 'No recordings' : Title of an empty list of records.
+
+
+
+ recordingsVocalLabel
+ 'Vocal' : Label for recording type that is a vocal message.
+
+
+
+ recordingsDelete
+ 'Are you sure you want to delete this item?' : Confirmation message for removing a record.
+
+
+
SettingsAdvanced
diff --git a/linphone-app/assets/languages/tr.ts b/linphone-app/assets/languages/tr.ts
index 9b6612885..ca4a4fbea 100644
--- a/linphone-app/assets/languages/tr.ts
+++ b/linphone-app/assets/languages/tr.ts
@@ -1782,6 +1782,11 @@ Buraya tıklayın: <a href="%1">%1</a>
'Check for updates' : Item menu for checking updates
Güncellemeleri denetle
+
+ recordings
+ 'Recordings' : Label for the recordings menu.
+
+
MainWindowTopMenuBar
@@ -1802,6 +1807,11 @@ Buraya tıklayın: <a href="%1">%1</a>
'Check for updates' : Item menu for checking updates
Güncellemeleri denetle
+
+ recordings
+ 'Recordings' : Label for the recordings menu.
+
+
ManageAccounts
@@ -2279,6 +2289,24 @@ Buraya tıklayın: <a href="%1">%1</a>
Kendiliğinden
+
+ Recordings
+
+ titleNoRecordings
+ 'No recordings' : Title of an empty list of records.
+
+
+
+ recordingsVocalLabel
+ 'Vocal' : Label for recording type that is a vocal message.
+
+
+
+ recordingsDelete
+ 'Are you sure you want to delete this item?' : Confirmation message for removing a record.
+
+
+
SettingsAdvanced
diff --git a/linphone-app/assets/languages/uk.ts b/linphone-app/assets/languages/uk.ts
index 5f7d0b467..bd25ac939 100644
--- a/linphone-app/assets/languages/uk.ts
+++ b/linphone-app/assets/languages/uk.ts
@@ -1802,6 +1802,11 @@
'Check for updates' : Item menu for checking updates
+
+ recordings
+ 'Recordings' : Label for the recordings menu.
+
+
MainWindowTopMenuBar
@@ -1822,6 +1827,11 @@
'Check for updates' : Item menu for checking updates
+
+ recordings
+ 'Recordings' : Label for the recordings menu.
+
+
ManageAccounts
@@ -2305,6 +2315,24 @@
+
+ Recordings
+
+ titleNoRecordings
+ 'No recordings' : Title of an empty list of records.
+
+
+
+ recordingsVocalLabel
+ 'Vocal' : Label for recording type that is a vocal message.
+
+
+
+ recordingsDelete
+ 'Are you sure you want to delete this item?' : Confirmation message for removing a record.
+
+
+
SettingsAdvanced
diff --git a/linphone-app/assets/languages/zh_CN.ts b/linphone-app/assets/languages/zh_CN.ts
index f715c304e..ca3b009d1 100644
--- a/linphone-app/assets/languages/zh_CN.ts
+++ b/linphone-app/assets/languages/zh_CN.ts
@@ -1782,6 +1782,11 @@
'Check for updates' : Item menu for checking updates
+
+ recordings
+ 'Recordings' : Label for the recordings menu.
+
+
MainWindowTopMenuBar
@@ -1802,6 +1807,11 @@
'Check for updates' : Item menu for checking updates
+
+ recordings
+ 'Recordings' : Label for the recordings menu.
+
+
ManageAccounts
@@ -2279,6 +2289,24 @@
自动
+
+ Recordings
+
+ titleNoRecordings
+ 'No recordings' : Title of an empty list of records.
+
+
+
+ recordingsVocalLabel
+ 'Vocal' : Label for recording type that is a vocal message.
+
+
+
+ recordingsDelete
+ 'Are you sure you want to delete this item?' : Confirmation message for removing a record.
+
+
+
SettingsAdvanced
diff --git a/linphone-app/resources.qrc b/linphone-app/resources.qrc
index efac25df6..6d8eb355d 100644
--- a/linphone-app/resources.qrc
+++ b/linphone-app/resources.qrc
@@ -135,6 +135,7 @@
assets/images/play_custom.svg
assets/images/recording_sign.svg
assets/images/record_custom.svg
+ assets/images/recordings_custom.svg
assets/images/remove_participant_custom.svg
assets/images/screen_sharing_custom.svg
assets/images/screenshot_custom.svg
@@ -481,6 +482,7 @@
ui/views/App/Main/MainWindowMenuBar.qml
ui/views/App/Main/MainWindow.qml
ui/views/App/Main/MainWindowTopMenuBar.qml
+ ui/views/App/Main/Recordings.qml
ui/views/App/Settings/Dialogs/SettingsLdapEdit.qml
ui/views/App/Settings/Dialogs/SettingsSipAccountsEdit.js
ui/views/App/Settings/Dialogs/SettingsSipAccountsEdit.qml
@@ -533,6 +535,7 @@
ui/views/App/Styles/Main/InviteFriendsStyle.qml
ui/views/App/Styles/Main/HistoryViewStyle.qml
ui/views/App/Styles/Main/MainWindowStyle.qml
+ ui/views/App/Styles/Main/RecordingsStyle.qml
ui/views/App/Styles/qmldir
ui/views/App/Styles/Settings/Dialogs/SettingsSipAccountsEditStyle.qml
ui/views/App/Styles/Settings/Dialogs/SettingsVideoPreviewStyle.qml
diff --git a/linphone-app/src/app/App.cpp b/linphone-app/src/app/App.cpp
index 5684a9931..861ff4562 100644
--- a/linphone-app/src/app/App.cpp
+++ b/linphone-app/src/app/App.cpp
@@ -676,6 +676,7 @@ void App::registerTypes () {
registerType("HistoryProxyModel");
registerType("LdapProxyModel");
registerType("ParticipantImdnStateProxyModel");
+ registerType("RecordingProxyModel");
registerType("SipAddressesProxyModel");
registerType("SearchSipAddressesModel");
registerType("SearchSipAddressesProxyModel");
@@ -711,6 +712,7 @@ void App::registerTypes () {
registerUncreatableType("ContactsImporterModel");
registerUncreatableType("ContentModel");
registerUncreatableType("ContentListModel");
+ registerUncreatableType("FileMediaModel");
registerUncreatableType("HistoryModel");
registerUncreatableType("LdapModel");
registerUncreatableType("RecorderModel");
diff --git a/linphone-app/src/app/proxyModel/ProxyListModel.hpp b/linphone-app/src/app/proxyModel/ProxyListModel.hpp
index 704daf38d..22ba8a5f0 100644
--- a/linphone-app/src/app/proxyModel/ProxyListModel.hpp
+++ b/linphone-app/src/app/proxyModel/ProxyListModel.hpp
@@ -86,16 +86,18 @@ public:
virtual bool remove(QObject *itemToRemove) override{
bool removed = false;
- qInfo() << QStringLiteral("Removing ") << itemToRemove->metaObject()->className() << QStringLiteral(" : ") << itemToRemove;
- int index = 0;
- for(auto item : mList)
- if( item == itemToRemove) {
- removed = removeRow(index);
- break;
- }else
- ++index;
- if( !removed)
- qWarning() << QStringLiteral("Unable to remove ") << itemToRemove->metaObject()->className() << QStringLiteral(" : ") << itemToRemove;
+ if(itemToRemove){
+ qInfo() << QStringLiteral("Removing ") << itemToRemove->metaObject()->className() << QStringLiteral(" : ") << itemToRemove;
+ int index = 0;
+ for(auto item : mList)
+ if( item == itemToRemove) {
+ removed = removeRow(index);
+ break;
+ }else
+ ++index;
+ if( !removed)
+ qWarning() << QStringLiteral("Unable to remove ") << itemToRemove->metaObject()->className() << QStringLiteral(" : ") << itemToRemove;
+ }
return removed;
}
virtual bool remove(QSharedPointer itemToRemove){
diff --git a/linphone-app/src/components/Components.hpp b/linphone-app/src/components/Components.hpp
index 52268068a..4545387a1 100644
--- a/linphone-app/src/components/Components.hpp
+++ b/linphone-app/src/components/Components.hpp
@@ -54,6 +54,7 @@
#include "core/CoreManager.hpp"
#include "file/FileDownloader.hpp"
#include "file/FileExtractor.hpp"
+#include "file/FileMediaModel.hpp"
#include "history/HistoryProxyModel.hpp"
#include "ldap/LdapModel.hpp"
#include "ldap/LdapListModel.hpp"
@@ -71,6 +72,8 @@
#include "presence/OwnPresenceModel.hpp"
#include "recorder/RecorderModel.hpp"
#include "recorder/RecorderManager.hpp"
+#include "recorder/RecordingListModel.hpp"
+#include "recorder/RecordingProxyModel.hpp"
#include "settings/AccountSettingsModel.hpp"
#include "settings/SettingsModel.hpp"
#include "search/SearchResultModel.hpp"
diff --git a/linphone-app/src/components/call/CallModel.cpp b/linphone-app/src/components/call/CallModel.cpp
index a62957cdc..dd8952ea1 100644
--- a/linphone-app/src/components/call/CallModel.cpp
+++ b/linphone-app/src/components/call/CallModel.cpp
@@ -1316,7 +1316,7 @@ QString CallModel::generateSavedFilename () const {
QString CallModel::generateSavedFilename (const QString &from, const QString &to) {
auto escape = [](const QString &str) {
- constexpr char ReservedCharacters[] = "[<|>|:|\"|/|\\\\|\\?|\\*|\\+|\\|]+";
+ constexpr char ReservedCharacters[] = "[<|>|:|\"|/|\\\\|\\?|\\*|\\+|\\||_|-]+";
static QRegularExpression regexp(ReservedCharacters);
return QString(str).replace(regexp, "");
};
@@ -1325,3 +1325,35 @@ QString CallModel::generateSavedFilename (const QString &from, const QString &to
.arg(escape(from))
.arg(escape(to));
}
+
+QStringList CallModel::splitSavedFilename(const QString& filename){
+ QStringList fields = filename.split('_');
+ if(fields.size() == 4 && fields[0].split('-').size() == 3 && fields[1].split('-').size() == 3){
+ return fields;
+ }else
+ return QStringList(filename);
+}
+
+QDateTime CallModel::getDateTimeSavedFilename(const QString& filename){
+ auto fields = splitSavedFilename(filename);
+ if(fields.size() > 1)
+ return QDateTime::fromString(fields[0] + "_" +fields[1], "yyyy-MM-dd_hh-mm-ss");
+ else
+ return QDateTime();
+}
+
+QString CallModel::getFromSavedFilename(const QString& filename){
+ auto fields = splitSavedFilename(filename);
+ if(fields.size() > 1)
+ return fields[2];
+ else
+ return "";
+}
+
+QString CallModel::getToSavedFilename(const QString& filename){
+ auto fields = splitSavedFilename(filename);
+ if(fields.size() > 1)
+ return fields[3];
+ else
+ return "";
+}
diff --git a/linphone-app/src/components/call/CallModel.hpp b/linphone-app/src/components/call/CallModel.hpp
index a4bd3e04e..db9cae4c7 100644
--- a/linphone-app/src/components/call/CallModel.hpp
+++ b/linphone-app/src/components/call/CallModel.hpp
@@ -320,8 +320,12 @@ public:
QString generateSavedFilename () const;
+// Format : Date_Time_From_To
static QString generateSavedFilename (const QString &from, const QString &to);
-
+ static QStringList splitSavedFilename(const QString& filename);// If doesn't match to generateSavedFilename, return filename
+ static QDateTime getDateTimeSavedFilename(const QString& filename);
+ static QString getFromSavedFilename(const QString& filename);
+ static QString getToSavedFilename(const QString& filename);
private:
void connectTo(CallListener * listener);
diff --git a/linphone-app/src/components/camera/Camera.cpp b/linphone-app/src/components/camera/Camera.cpp
index e4f15b93d..31ab63864 100644
--- a/linphone-app/src/components/camera/Camera.cpp
+++ b/linphone-app/src/components/camera/Camera.cpp
@@ -27,6 +27,7 @@
#include "components/core/CoreManager.hpp"
#include "components/participant/ParticipantDeviceModel.hpp"
#include "components/settings/SettingsModel.hpp"
+#include "components/sound-player/SoundPlayer.hpp"
#include "Camera.hpp"
#include "CameraDummy.hpp"
@@ -104,6 +105,9 @@ void Camera::resetWindowId() const{
oldRenderer = (QQuickFramebufferObject::Renderer *)core->getNativeVideoWindowId();
if(oldRenderer)
core->setNativeVideoWindowId(NULL);
+ }else if(mWindowIdLocation == Player){
+ if(mLinphonePlayer && mLinphonePlayer->getLinphonePlayer())
+ mLinphonePlayer->getLinphonePlayer()->setWindowId(nullptr);
}
qDebug() << "[Camera] Removed " << oldRenderer << " at " << mWindowIdLocation << " for " << this;
mIsWindowIdSet = false;
@@ -148,6 +152,9 @@ void Camera::updateWindowIdLocation(){
setWindowIdLocation(WindowIdLocation::Device);
useDefaultWindow = false;
}
+ }else if( mLinphonePlayer){
+ setWindowIdLocation(WindowIdLocation::Player);
+ useDefaultWindow = false;
}
if(useDefaultWindow){
setWindowIdLocation(WindowIdLocation::Core);
@@ -163,6 +170,10 @@ void Camera::removeCallModel(){
mCallModel = nullptr;
}
+void Camera::removeLinphonePlayer(){
+ mLinphonePlayer = nullptr;
+}
+
QQuickFramebufferObject::Renderer *Camera::createRenderer () const {
QQuickFramebufferObject::Renderer * renderer = NULL;
if(mWindowIdLocation == CorePreview){
@@ -194,6 +205,14 @@ QQuickFramebufferObject::Renderer *Camera::createRenderer () const {
renderer = (QQuickFramebufferObject::Renderer *) CoreManager::getInstance()->getCore()->createNativeVideoWindowId();
if(renderer)
CoreManager::getInstance()->getCore()->setNativeVideoWindowId(renderer);
+ }else if( mWindowIdLocation == Player){
+ auto player = mLinphonePlayer->getLinphonePlayer();
+ if(player){
+ qDebug() << "[Camera] Setting Camera to Player";
+ renderer = (QQuickFramebufferObject::Renderer *) player->createWindowId();
+ if(renderer)
+ player->setWindowId(renderer);
+ }
}
if( !renderer){
QTimer::singleShot(1, this, &Camera::isNotReady);// Workaround for const createRenderer
@@ -227,6 +246,10 @@ ParticipantDeviceModel * Camera::getParticipantDeviceModel() const{
return mParticipantDeviceModel;
}
+SoundPlayer * Camera::getLinphonePlayer() const{
+ return mLinphonePlayer;
+}
+
void Camera::setCallModel (CallModel *callModel) {
if (mCallModel != callModel) {
if( mCallModel){
@@ -275,6 +298,17 @@ void Camera::setParticipantDeviceModel(ParticipantDeviceModel * participantDevic
emit participantDeviceModelChanged(mParticipantDeviceModel);
}
}
+void Camera::setLinphonePlayer(SoundPlayer *player){
+ if (mLinphonePlayer!= player) {
+ if( mLinphonePlayer)
+ disconnect(mLinphonePlayer, &QObject::destroyed, this, &Camera::removeLinphonePlayer);
+ mLinphonePlayer = player;
+ connect(mLinphonePlayer, &QObject::destroyed, this, &Camera::removeLinphonePlayer);
+ updateWindowIdLocation();
+ update();
+ emit linphonePlayerChanged(mLinphonePlayer);
+ }
+}
void Camera::isReady(){
setIsReady(true);
diff --git a/linphone-app/src/components/camera/Camera.hpp b/linphone-app/src/components/camera/Camera.hpp
index afb78e4d7..c544d05f4 100644
--- a/linphone-app/src/components/camera/Camera.hpp
+++ b/linphone-app/src/components/camera/Camera.hpp
@@ -27,6 +27,8 @@
#include
#include
+#include "components/sound-player/SoundPlayer.hpp"
+
// =============================================================================
namespace linphone {
@@ -35,6 +37,7 @@ namespace linphone {
class CallModel;
class ParticipantDeviceModel;
+
// -----------------------------------------------------------------------------
class Camera : public QQuickFramebufferObject {
@@ -44,12 +47,14 @@ class Camera : public QQuickFramebufferObject {
Q_PROPERTY(ParticipantDeviceModel * participantDeviceModel READ getParticipantDeviceModel WRITE setParticipantDeviceModel NOTIFY participantDeviceModelChanged)
Q_PROPERTY(bool isPreview READ getIsPreview WRITE setIsPreview NOTIFY isPreviewChanged);
Q_PROPERTY(bool isReady READ getIsReady WRITE setIsReady NOTIFY isReadyChanged);
+ Q_PROPERTY(SoundPlayer * linphonePlayer READ getLinphonePlayer WRITE setLinphonePlayer NOTIFY linphonePlayerChanged)
typedef enum{
None = -1,
CorePreview = 0,
Call,
Device,
+ Player,
Core
}WindowIdLocation;
@@ -77,24 +82,28 @@ signals:
void participantDeviceModelChanged(ParticipantDeviceModel *participantDeviceModel);
void requestNewRenderer();
void videoDefinitionChanged();
+ void linphonePlayerChanged(SoundPlayer * linphonePlayer);
private:
CallModel *getCallModel () const;
bool getIsPreview () const;
bool getIsReady () const;
ParticipantDeviceModel * getParticipantDeviceModel() const;
+ SoundPlayer * getLinphonePlayer() const;
void setCallModel (CallModel *callModel);
void setIsPreview (bool status);
void setIsReady(bool status);
void setParticipantDeviceModel(ParticipantDeviceModel * participantDeviceModel);
- void setWindowIdLocation(const WindowIdLocation& location);
+ void setLinphonePlayer(SoundPlayer *player);
+ void setWindowIdLocation(const WindowIdLocation& location);
void activatePreview();
void deactivatePreview();
void updateWindowIdLocation();
void removeParticipantDeviceModel();
void removeCallModel();
+ void removeLinphonePlayer();
QVariantMap mLastVideoDefinition;
QTimer mLastVideoDefinitionChecker;
@@ -103,6 +112,7 @@ private:
bool mIsReady = false;
CallModel *mCallModel = nullptr;
ParticipantDeviceModel *mParticipantDeviceModel = nullptr;
+ SoundPlayer * mLinphonePlayer = nullptr;
WindowIdLocation mWindowIdLocation = None;
mutable bool mIsWindowIdSet = false;
diff --git a/linphone-app/src/components/file/FileMediaModel.cpp b/linphone-app/src/components/file/FileMediaModel.cpp
new file mode 100644
index 000000000..e36b9ab2a
--- /dev/null
+++ b/linphone-app/src/components/file/FileMediaModel.cpp
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2010-2023 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 .
+ */
+
+#include "FileMediaModel.hpp"
+
+#include
+
+#include "app/App.hpp"
+
+#include "components/call/CallModel.hpp"
+#include "components/recorder/RecorderModel.hpp"
+#include "components/sound-player/SoundPlayer.hpp"
+
+
+// =============================================================================
+
+FileMediaModel::FileMediaModel (const QString& path, QObject * parent) :mFileInfo(path), QObject(parent) {
+ if(path.isEmpty()) return;
+ init();
+}
+
+FileMediaModel::FileMediaModel (const QFileInfo& fileInfo, QObject * parent) :mFileInfo(fileInfo), QObject(parent) {
+ init();
+}
+
+FileMediaModel::~FileMediaModel(){
+}
+
+QSharedPointer FileMediaModel::create(const QString& path){
+ return FileMediaModel::create(QFileInfo(path));
+}
+
+QSharedPointer FileMediaModel::create(const QFileInfo& fileInfo){
+ auto model = QSharedPointer::create(fileInfo);
+ return model;
+}
+
+void FileMediaModel::init(){
+ QString baseName = getBaseName();
+ SoundPlayer soundPlayer;
+ soundPlayer.setSource(mFileInfo.absoluteFilePath());
+ if(soundPlayer.open()){
+ mDuration = soundPlayer.getDuration();
+ if(CallModel::splitSavedFilename(baseName).size() > 1)
+ mType = IS_CALL_RECORD;
+ else if( RecorderModel::splitSavedFilename(baseName).size() > 1)
+ mType = IS_VOICE_RECORD;
+ else
+ mType = IS_PLAYABLE;
+ }else if(CallModel::splitSavedFilename(baseName).size() > 1)
+ mType = IS_SNAPSHOT;
+ else
+ mType = IS_UNKNOWN;
+}
+// -----------------------------------------------------------------------------
+
+QString FileMediaModel::getBaseName() const{
+ return mFileInfo.baseName();
+}
+
+QString FileMediaModel::getFilePath() const{
+ return mFileInfo.absoluteFilePath();
+}
+
+int FileMediaModel::getDuration() const{
+ return mDuration;
+}
+
+FileMediaModel::FILE_TYPE FileMediaModel::getType() const{
+ return mType;
+}
+
+QString FileMediaModel::getFrom()const{
+ QString baseName = getBaseName();
+ switch(mType){
+ case IS_CALL_RECORD: case IS_SNAPSHOT:
+ return CallModel::getFromSavedFilename(baseName);
+ break;
+ case IS_VOICE_RECORD:
+ return "";
+ break;
+ default:{
+ return "";
+ }
+ }
+}
+
+QString FileMediaModel::getTo()const{
+ QString baseName = getBaseName();
+ switch(mType){
+ case IS_CALL_RECORD: case IS_SNAPSHOT:
+ return CallModel::getToSavedFilename(baseName);
+ break;
+ case IS_VOICE_RECORD:
+ return "";
+ break;
+ default:{
+ return "";
+ }
+ }
+}
+
+QDateTime FileMediaModel::getCreationDateTime() const{
+ QString baseName;
+ switch(mType){
+ case IS_CALL_RECORD: case IS_SNAPSHOT:
+ baseName = getBaseName();
+ return CallModel::getDateTimeSavedFilename(baseName);
+ break;
+ case IS_VOICE_RECORD:
+ baseName = getBaseName();
+ return RecorderModel::getDateTimeSavedFilename(baseName);
+ break;
+ default:{
+ QDateTime creationDate = mFileInfo.birthTime();
+ return creationDate.isValid() ? creationDate : mFileInfo.lastModified();
+ }
+ }
+}
+
+QStringList FileMediaModel::getParsedBaseName() const{
+ QString baseName = getBaseName();
+ switch(mType){
+ case IS_CALL_RECORD: case IS_SNAPSHOT:
+ return CallModel::splitSavedFilename(baseName);
+ break;
+ case IS_VOICE_RECORD:
+ return RecorderModel::splitSavedFilename(baseName);
+ break;
+ default:{
+ return QStringList(baseName);
+ }
+ }
+}
diff --git a/linphone-app/src/components/file/FileMediaModel.hpp b/linphone-app/src/components/file/FileMediaModel.hpp
new file mode 100644
index 000000000..f26362321
--- /dev/null
+++ b/linphone-app/src/components/file/FileMediaModel.hpp
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2010-2023 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 .
+ */
+
+#ifndef FILE_MEDIA_MODEL_H_
+#define FILE_MEDIA_MODEL_H_
+
+#include
+#include
+#include
+#include
+#include
+
+// =============================================================================
+
+class FileMediaModel : public QObject {
+ Q_OBJECT
+ Q_PROPERTY(QString baseName READ getBaseName CONSTANT)
+ Q_PROPERTY(QStringList parsedBaseName READ getParsedBaseName CONSTANT)
+ Q_PROPERTY(QString filePath READ getFilePath CONSTANT)
+ Q_PROPERTY(QDateTime creationDateTime READ getCreationDateTime CONSTANT)
+ Q_PROPERTY(FILE_TYPE type READ getType CONSTANT)
+// App Custom
+ Q_PROPERTY(int duration READ getDuration CONSTANT)
+ Q_PROPERTY(QString from READ getFrom CONSTANT)
+ Q_PROPERTY(QString to READ getTo CONSTANT)
+public:
+ enum FILE_TYPE{
+ IS_CALL_RECORD,
+ IS_VOICE_RECORD,
+ IS_SNAPSHOT,
+ IS_PLAYABLE,// playable but nor call nor voice
+ IS_UNKNOWN
+ };
+ Q_ENUM(FILE_TYPE)
+ FileMediaModel(const QString& path, QObject * parent = nullptr);
+ FileMediaModel(const QFileInfo& fileInfo, QObject * parent = nullptr);
+ ~FileMediaModel();
+ static QSharedPointer create(const QString& path);
+ static QSharedPointer create(const QFileInfo& fileInfo);
+
+ void init();
+
+ QString getBaseName() const;
+ QString getFilePath() const;
+ int getDuration() const;
+ QDateTime getCreationDateTime() const;
+ QStringList getParsedBaseName() const;
+ FILE_TYPE getType()const;
+ QString getFrom()const;
+ QString getTo()const;
+
+private:
+ QFileInfo mFileInfo;
+ int mDuration = -1; // Set by LinphonePlayer when cration an instance of FileModel
+ FILE_TYPE mType = IS_UNKNOWN;
+};
+
+#endif
diff --git a/linphone-app/src/components/other/colors/ColorListModel.hpp b/linphone-app/src/components/other/colors/ColorListModel.hpp
index e31b99411..5b8539bfc 100644
--- a/linphone-app/src/components/other/colors/ColorListModel.hpp
+++ b/linphone-app/src/components/other/colors/ColorListModel.hpp
@@ -191,6 +191,17 @@ class ColorListModel : public ProxyListModel {
ADD_COLOR("ma_d_b_fg", "white", "[M] Main disabled button : foreground")
ADD_COLOR("ma_h_b_fg", "white", "[M] Main hovered button : foreground")
ADD_COLOR("ma_p_b_fg", "white", "[M] Main pressed button : foreground")
+
+// Inverse
+ ADD_COLOR("ma_n_b_inv_bg", "transparent", "[M] Main normal button : inverse background")
+ ADD_COLOR("ma_d_b_inv_bg", "transparent", "[M] Main disabled button : inverse background")
+ ADD_COLOR("ma_h_b_inv_bg", "transparent", "[M] Main hovered button : inverse background")
+ ADD_COLOR("ma_p_b_inv_bg", "transparent", "[M] Main pressed button : inverse background")
+
+ ADD_COLOR_WITH_LINK("ma_n_b_inv_fg", "", "[M] Main normal button : inverse foreground", "i")
+ ADD_COLOR_WITH_LINK("ma_d_b_inv_fg", "", "[M] Main disabled button : inverse foreground", "primary_d")
+ ADD_COLOR_WITH_LINK("ma_h_b_inv_fg", "", "[M] Main hovered button : inverse foreground", "b")
+ ADD_COLOR_WITH_LINK("ma_p_b_inv_fg", "", "[M] Main pressed button : inverse foreground", "m")
//-------------------------------------
// Accept Actions : like accepting a call
ADD_COLOR_WITH_LINK("a_n_b_bg", "", "[M] Accept normal button : background", "primary_accept")
diff --git a/linphone-app/src/components/recorder/RecorderModel.cpp b/linphone-app/src/components/recorder/RecorderModel.cpp
index 75dd5a114..955875022 100644
--- a/linphone-app/src/components/recorder/RecorderModel.cpp
+++ b/linphone-app/src/components/recorder/RecorderModel.cpp
@@ -64,6 +64,23 @@ QString RecorderModel::getFile()const{
return Utils::coreStringToAppString(mRecorder->getFile());
}
+QStringList RecorderModel::splitSavedFilename(const QString& filename){
+ QStringList fields = filename.split('_');
+ if(fields.size() == 3 && fields[0] == "vocal" && fields[1].split('-').size() == 3
+ && fields[2].split('-').size() == 4){
+ return fields;
+ }else
+ return QStringList(filename);
+}
+
+QDateTime RecorderModel::getDateTimeSavedFilename(const QString& filename){
+ auto fields = splitSavedFilename(filename);
+ if(fields.size() > 1)
+ return QDateTime::fromString(fields[1] + "_" +fields[2], "yyyy-MM-dd_hh-mm-ss-zzz");
+ else
+ return QDateTime();;
+}
+
void RecorderModel::start(){
bool soFarSoGood;
QString filename = QStringLiteral("vocal_%1.mkv")
diff --git a/linphone-app/src/components/recorder/RecorderModel.hpp b/linphone-app/src/components/recorder/RecorderModel.hpp
index db9359a07..77b4550c9 100644
--- a/linphone-app/src/components/recorder/RecorderModel.hpp
+++ b/linphone-app/src/components/recorder/RecorderModel.hpp
@@ -44,6 +44,9 @@ public:
LinphoneEnums::RecorderState getState() const;
Q_INVOKABLE QString getFile()const;
+ static QStringList splitSavedFilename(const QString& filename);// If doesn't match to generateSavedFilename, return filename
+ static QDateTime getDateTimeSavedFilename(const QString& filename);
+
Q_INVOKABLE void start();
Q_INVOKABLE void pause();
Q_INVOKABLE void stop();
diff --git a/linphone-app/src/components/recorder/RecordingListModel.cpp b/linphone-app/src/components/recorder/RecordingListModel.cpp
new file mode 100644
index 000000000..309dee249
--- /dev/null
+++ b/linphone-app/src/components/recorder/RecordingListModel.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2010-2023 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 .
+ */
+
+#include "app/App.hpp"
+#include "components/core/CoreManager.hpp"
+#include "components/file/FileMediaModel.hpp"
+#include "components/settings/AccountSettingsModel.hpp"
+#include "components/settings/SettingsModel.hpp"
+#include "components/sip-addresses/SipAddressesModel.hpp"
+#include "utils/Utils.hpp"
+
+#include "RecordingListModel.hpp"
+
+#include
+#include
+
+
+// =============================================================================
+
+RecordingListModel::RecordingListModel (QObject *parent) : ProxyListModel(parent) {
+ load();
+}
+
+RecordingListModel::~RecordingListModel(){
+ mList.clear();
+}
+
+// -----------------------------------------------------------------------------
+
+void RecordingListModel::load(){
+ resetData();
+ QString folder = CoreManager::getInstance()->getSettingsModel()->getSavedCallsFolder();
+ qInfo() << "[Recordings] looking for recordings in " << CoreManager::getInstance()->getSettingsModel()->getSavedCallsFolder();
+ QDir dir( folder );
+ QList> files;
+ foreach(QFileInfo file, dir.entryInfoList(QDir::Files | QDir::NoDotAndDotDot)) {
+ auto recording = FileMediaModel::create(file);
+ if(recording) {
+ App::getInstance()->getEngine()->setObjectOwnership(recording.get(), QQmlEngine::CppOwnership);// Avoid QML to destroy it when passing by Q_INVOKABLE
+ files << recording;
+ }
+ }
+ if(files.size() > 0)
+ add(files);
+}
+
+QHash RecordingListModel::roleNames () const {
+ QHash roles = ProxyListModel::roleNames();
+ roles[Qt::DisplayRole+1] = "$sectionDate";
+ return roles;
+}
+
+QVariant RecordingListModel::data (const QModelIndex &index, int role) const{
+ int row = index.row();
+ if (!index.isValid() || row < 0 || row >= mList.count())
+ return QVariant();
+ if(role == Qt::DisplayRole +1){
+ return QVariant::fromValue(mList[row].objectCast()->getCreationDateTime().date());
+ }else
+ return ProxyListModel::data(index, role);
+}
diff --git a/linphone-app/src/components/recorder/RecordingListModel.hpp b/linphone-app/src/components/recorder/RecordingListModel.hpp
new file mode 100644
index 000000000..d22c9f02a
--- /dev/null
+++ b/linphone-app/src/components/recorder/RecordingListModel.hpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2010-2023 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 .
+ */
+
+#ifndef RECORDING_LIST_MODEL_H_
+#define RECORDING_LIST_MODEL_H_
+
+#include "app/proxyModel/ProxyListModel.hpp"
+#include "components/sound-player/SoundPlayer.hpp"
+
+// =============================================================================
+
+class RecordingListModel : public ProxyListModel {
+ Q_OBJECT
+public:
+ RecordingListModel (QObject *parent = Q_NULLPTR);
+ virtual ~RecordingListModel();
+
+ void load();
+
+ QHash roleNames () const override;
+ virtual QVariant data (const QModelIndex &index, int role = Qt::DisplayRole) const override;
+ /*
+ Q_INVOKABLE void remove (SoundPlayer *player);
+ Q_INVOKABLE SoundPlayer* getSoundPlayer() const;
+ */
+
+};
+#endif
diff --git a/linphone-app/src/components/recorder/RecordingProxyModel.cpp b/linphone-app/src/components/recorder/RecordingProxyModel.cpp
new file mode 100644
index 000000000..1e829df13
--- /dev/null
+++ b/linphone-app/src/components/recorder/RecordingProxyModel.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2010-2023 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 .
+ */
+
+#include "RecordingProxyModel.hpp"
+
+#include "components/core/CoreManager.hpp"
+#include "components/settings/AccountSettingsModel.hpp"
+#include "components/sip-addresses/SipAddressesModel.hpp"
+#include "components/conference/ConferenceModel.hpp"
+#include "components/conferenceInfo/ConferenceInfoModel.hpp"
+#include "components/file/FileMediaModel.hpp"
+#include "components/sound-player/SoundPlayer.hpp"
+#include "utils/Utils.hpp"
+
+#include "RecordingListModel.hpp"
+
+#include
+
+
+// =============================================================================
+
+// -----------------------------------------------------------------------------
+
+RecordingProxyModel::RecordingProxyModel (QObject *parent) : SortFilterProxyModel(parent) {
+ auto list = new RecordingListModel(this);
+ setSourceModel(list);
+ sort(0);
+}
+
+// -----------------------------------------------------------------------------
+
+void RecordingProxyModel::remove(FileMediaModel * fileModel){
+ QFile file(fileModel->getFilePath());
+ if(file.remove())
+ qobject_cast(sourceModel())->remove(fileModel);
+}
+
+bool RecordingProxyModel::lessThan (const QModelIndex &left, const QModelIndex &right) const {
+ const FileMediaModel* a = sourceModel()->data(left).value();
+ const FileMediaModel* b = sourceModel()->data(right).value();
+
+ return a->getCreationDateTime() > b->getCreationDateTime();
+}
diff --git a/linphone-app/src/components/recorder/RecordingProxyModel.hpp b/linphone-app/src/components/recorder/RecordingProxyModel.hpp
new file mode 100644
index 000000000..21715ae65
--- /dev/null
+++ b/linphone-app/src/components/recorder/RecordingProxyModel.hpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2023 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 .
+ */
+
+#ifndef RECORDING_PROXY_MODEL_H_
+#define RECORDING_PROXY_MODEL_H_
+
+#include "app/proxyModel/SortFilterProxyModel.hpp"
+#include
+
+// =============================================================================
+
+class FileMediaModel;
+
+class RecordingProxyModel : public SortFilterProxyModel {
+ Q_OBJECT
+
+public:
+ RecordingProxyModel ( QObject *parent = Q_NULLPTR);
+
+ //bool filterAcceptsRow (int sourceRow, const QModelIndex &sourceParent) const override;
+ bool lessThan (const QModelIndex &left, const QModelIndex &right) const override;
+ Q_INVOKABLE void remove(FileMediaModel * file);
+ //Q_INVOKABLE int getCount() const;
+};
+
+#endif
diff --git a/linphone-app/src/components/sound-player/SoundPlayer.cpp b/linphone-app/src/components/sound-player/SoundPlayer.cpp
index eb8002dbe..0ba8597fc 100644
--- a/linphone-app/src/components/sound-player/SoundPlayer.cpp
+++ b/linphone-app/src/components/sound-player/SoundPlayer.cpp
@@ -93,26 +93,33 @@ void SoundPlayer::pause () {
emit playbackStateChanged(mPlaybackState);
}
-void SoundPlayer::play () {
- if (mPlaybackState == SoundPlayer::PlayingState || mSource == "")
- return;
+bool SoundPlayer::open(){
+ return mInternalPlayer->open(Utils::appStringToCoreString(mSource)) == 0;
+}
+
+bool SoundPlayer::play () {
+ if (mPlaybackState == SoundPlayer::PlayingState)
+ return true;
+ else if(mSource == "")
+ return false;
if (
(mPlaybackState == SoundPlayer::StoppedState || mPlaybackState == SoundPlayer::ErrorState) &&
- mInternalPlayer->open(Utils::appStringToCoreString(mSource))
+ !open()
) {
qWarning() << QStringLiteral("Unable to open: `%1`").arg(mSource);
- return;
+ return false;
}
if (mInternalPlayer->start()
) {
setError(QStringLiteral("Unable to play: `%1`").arg(mSource));
- return;
+ return false;
}
mForceCloseTimer->start();
mPlaybackState = SoundPlayer::PlayingState;
emit playing();
emit playbackStateChanged(mPlaybackState);
+ return true;
}
void SoundPlayer::stop () {
@@ -131,6 +138,10 @@ int SoundPlayer::getPosition () const {
return mInternalPlayer->getCurrentPosition();
}
+bool SoundPlayer::hasVideo() const{
+ return mInternalPlayer->getIsVideoAvailable();
+}
+
// -----------------------------------------------------------------------------
void SoundPlayer::buildInternalPlayer () {
@@ -229,3 +240,17 @@ void SoundPlayer::setPlaybackState (PlaybackState playbackState) {
int SoundPlayer::getDuration () const {
return mInternalPlayer->getDuration();
}
+
+QDateTime SoundPlayer::getCreationDateTime() const{
+ QFileInfo fileInfo(mSource);
+ QDateTime creationDate = fileInfo.birthTime();
+ return creationDate.isValid() ? creationDate : fileInfo.lastModified();
+}
+
+QString SoundPlayer::getBaseName() const{
+ return QFileInfo(mSource).baseName();
+}
+
+std::shared_ptr SoundPlayer::getLinphonePlayer()const{
+ return mInternalPlayer;
+}
\ No newline at end of file
diff --git a/linphone-app/src/components/sound-player/SoundPlayer.hpp b/linphone-app/src/components/sound-player/SoundPlayer.hpp
index c0293abb3..111033320 100644
--- a/linphone-app/src/components/sound-player/SoundPlayer.hpp
+++ b/linphone-app/src/components/sound-player/SoundPlayer.hpp
@@ -40,9 +40,11 @@ class SoundPlayer : public QObject {
Q_OBJECT
Q_PROPERTY(QString source READ getSource WRITE setSource NOTIFY sourceChanged)
+ Q_PROPERTY(QString baseName READ getBaseName NOTIFY sourceChanged)
Q_PROPERTY(PlaybackState playbackState READ getPlaybackState WRITE setPlaybackState NOTIFY playbackStateChanged)
Q_PROPERTY(int duration READ getDuration NOTIFY sourceChanged)
Q_PROPERTY(bool isRinger MEMBER mIsRinger)
+ Q_PROPERTY(QDateTime creationDateTime READ getCreationDateTime NOTIFY sourceChanged)
public:
enum PlaybackState {
@@ -56,13 +58,23 @@ public:
SoundPlayer (QObject *parent = Q_NULLPTR);
~SoundPlayer ();
+ bool open();
Q_INVOKABLE void pause ();
- Q_INVOKABLE void play ();
+ Q_INVOKABLE bool play ();
Q_INVOKABLE void stop ();
Q_INVOKABLE void seek (int offset);
Q_INVOKABLE int getPosition () const;
+ Q_INVOKABLE bool hasVideo() const;// Call it after playing a video because the detection is not outside this scope.
+
+ int getDuration () const;
+ QDateTime getCreationDateTime() const;
+ QString getBaseName() const;
+ std::shared_ptr getLinphonePlayer()const;
+
+ QString getSource () const;
+ void setSource (const QString &source);
signals:
void sourceChanged (const QString &source);
@@ -83,13 +95,10 @@ private:
void setError (const QString &message);
- QString getSource () const;
- void setSource (const QString &source);
-
PlaybackState getPlaybackState () const;
void setPlaybackState (PlaybackState playbackState);
- int getDuration () const;
+
QString mSource;
PlaybackState mPlaybackState = StoppedState;
diff --git a/linphone-app/ui/modules/Linphone/Camera/CameraItem.qml b/linphone-app/ui/modules/Linphone/Camera/CameraItem.qml
index 7e0d04d3b..2eca6d422 100644
--- a/linphone-app/ui/modules/Linphone/Camera/CameraItem.qml
+++ b/linphone-app/ui/modules/Linphone/Camera/CameraItem.qml
@@ -18,6 +18,7 @@ Item {
property bool isCameraFromDevice: true
property ParticipantDeviceModel currentDevice
property CallModel callModel
+ property SoundPlayer linphonePlayer
property bool isPreview: (!callModel && !container.currentDevice) || ( container.currentDevice && container.currentDevice.isMe)
property bool isFullscreen: false
property bool hideCamera: false
@@ -77,6 +78,7 @@ Item {
id: camera
Camera {
participantDeviceModel: container.currentDevice
+ linphonePlayer: container.linphonePlayer
call: container.isCameraFromDevice ? null : container.callModel
anchors.fill: parent
isPreview: container.isPreview
diff --git a/linphone-app/ui/modules/Linphone/Camera/CameraView.qml b/linphone-app/ui/modules/Linphone/Camera/CameraView.qml
index 9d1e00139..8f5414d65 100644
--- a/linphone-app/ui/modules/Linphone/Camera/CameraView.qml
+++ b/linphone-app/ui/modules/Linphone/Camera/CameraView.qml
@@ -15,6 +15,7 @@ Item{
id: mainItem
property alias currentDevice: camera.currentDevice
property alias callModel: camera.callModel
+ property alias linphonePlayer : camera.linphonePlayer
property alias hideCamera: camera.hideCamera
property alias isPaused: camera.isPaused
property alias isPreview: camera.isPreview
diff --git a/linphone-app/ui/views/App/Main/MainWindow.qml b/linphone-app/ui/views/App/Main/MainWindow.qml
index b60cc6661..17f76eda7 100644
--- a/linphone-app/ui/views/App/Main/MainWindow.qml
+++ b/linphone-app/ui/views/App/Main/MainWindow.qml
@@ -75,7 +75,6 @@ ApplicationWindow {
readonly property alias conferencesEntry: conferencesEntry
readonly property alias contentLoader: contentLoader
- //readonly property alias conferencesEntry: conferencesEntry
readonly property alias menu: menu
readonly property alias timeline: timeline
@@ -266,6 +265,10 @@ ApplicationWindow {
onClicked: toggled ? menuBar.close() : menuBar.open()// a bit useless as Menu will depopup on losing focus but this code is kept for giving idea
MainWindowMenuBar {
id: menuBar
+ onDisplayRecordings: {
+ timeline.model.unselectAll()
+ setView('Recordings')
+ }
}
}
}
@@ -325,6 +328,7 @@ ApplicationWindow {
}
}
+
ApplicationMenuEntry {
id: conferencesEntry
@@ -413,7 +417,12 @@ ApplicationWindow {
Loader{
id: customMenuBar
active:Qt.platform.os === 'osx'
- sourceComponent:MainWindowTopMenuBar{}
+ sourceComponent:MainWindowTopMenuBar{
+ onDisplayRecordings: {
+ timeline.model.unselectAll()
+ setView('Recordings')
+ }
+ }
}
Component.onCompleted: if(Qt.platform.os === 'osx') menuBar = customMenuBar
// ---------------------------------------------------------------------------
diff --git a/linphone-app/ui/views/App/Main/MainWindowMenuBar.qml b/linphone-app/ui/views/App/Main/MainWindowMenuBar.qml
index f02d0f489..5eafac0f1 100644
--- a/linphone-app/ui/views/App/Main/MainWindowMenuBar.qml
+++ b/linphone-app/ui/views/App/Main/MainWindowMenuBar.qml
@@ -18,6 +18,8 @@ Item {
menu.close()
}
+ signal displayRecordings()
+
// ---------------------------------------------------------------------------
// Shortcuts.
// ---------------------------------------------------------------------------
@@ -50,6 +52,11 @@ Item {
}
}
+ Shortcut {
+ id: recordingsShortcut
+ onActivated: menuParent.displayRecordings()
+ }
+
// ---------------------------------------------------------------------------
// Menu.
// ---------------------------------------------------------------------------
@@ -64,6 +71,12 @@ Item {
onTriggered: settingsShortcut.onActivated()
}
+ MenuItem{
+ //: 'Recordings' : Label for the recordings menu.
+ text: qsTr('recordings')
+ onTriggered: recordingsShortcut.onActivated()
+ }
+
MenuItem {
visible: CoreManager.initialized && SettingsModel.isCheckForUpdateAvailable()
//: 'Check for updates' : Item menu for checking updates
diff --git a/linphone-app/ui/views/App/Main/MainWindowTopMenuBar.qml b/linphone-app/ui/views/App/Main/MainWindowTopMenuBar.qml
index ee9425d5b..a4e8e8476 100644
--- a/linphone-app/ui/views/App/Main/MainWindowTopMenuBar.qml
+++ b/linphone-app/ui/views/App/Main/MainWindowTopMenuBar.qml
@@ -6,10 +6,12 @@ import Linphone 1.0
// =============================================================================
MenuBar {
+ id: menuBar
function open () {
menu.open()
}
-
+ signal displayRecordings()
+
// ---------------------------------------------------------------------------
// Menu.
// ---------------------------------------------------------------------------
@@ -25,6 +27,12 @@ MenuBar {
shortcut: StandardKey.Preferences
}
+ MenuItem {
+ //: 'Recordings' : Label for the recordings menu.
+ text: qsTr('recordings')
+ role: MenuItem.ApplicationSpecificRole
+ onTriggered: menuBar.displayRecordings()
+ }
MenuItem {
visible: CoreManager.initialized && SettingsModel.isCheckForUpdateAvailable()
diff --git a/linphone-app/ui/views/App/Main/Recordings.qml b/linphone-app/ui/views/App/Main/Recordings.qml
new file mode 100644
index 000000000..714dbb31f
--- /dev/null
+++ b/linphone-app/ui/views/App/Main/Recordings.qml
@@ -0,0 +1,291 @@
+import QtQuick 2.7
+import QtQuick.Controls 2.7
+import QtQuick.Layouts 1.10
+
+import App 1.0
+import Common 1.0
+import Linphone 1.0
+import Utils 1.0
+import UtilsCpp 1.0
+import ColorsList 1.0
+import Units 1.0
+
+
+import App.Styles 1.0
+
+// =============================================================================
+
+Item {
+ Item{
+ id: mainItem
+ anchors.fill: parent
+ anchors.topMargin : 15
+ anchors.bottomMargin : 15
+ anchors.leftMargin : 15
+ anchors.rightMargin : 0
+ Text {
+ id: noRec
+ anchors.centerIn: parent
+ //: 'No recordings' : Title of an empty list of records.
+ text: qsTr('titleNoRecordings')
+ visible : recordingsProxyModel.count === 0
+ color: RecordingsStyle.title.color
+ font.pointSize: RecordingsStyle.title.pointSize
+ }
+ Component {
+ id: sectionHeading
+ Form {
+ anchors.rightMargin : 10
+ required property string section
+ title: section
+ width: parent.width
+ height: 30
+ }
+ }
+ ScrollableListView {
+ anchors.fill: parent
+ id: recordingsList
+ spacing: 0
+ model: RecordingProxyModel {
+ id: recordingsProxyModel
+ }
+ section.property: '$sectionDate'
+ section.criteria: ViewSection.FullString
+ section.delegate: sectionHeading
+ delegate: Loader{
+ id: lineLoader
+ property bool isMedia: $modelData && ($modelData.type != FileMediaModel.IS_UNKNOWN && $modelData.type != FileMediaModel.IS_SNAPSHOT) // Test only extension because file can be encrypted.
+ property string title: ($modelData.type == FileMediaModel.IS_CALL_RECORD || $modelData.type == FileMediaModel.IS_SNAPSHOT
+ ? $modelData.from + ' => ' +$modelData.to
+ : $modelData.type == FileMediaModel.IS_VOICE_RECORD
+ //: 'Vocal' : Label for recording type that is a vocal message.
+ ? qsTr('recordingsVocalLabel')
+ : $modelData.baseName)
+ + ' - ' +UtilsCpp.toTimeString($modelData.creationDateTime)
+ sourceComponent: isMedia ? mediaComponent : fileComponent
+//--------------------------------------------------------------------------
+// MEDIA
+//--------------------------------------------------------------------------
+ Component{
+ id: mediaComponent
+ RowLayout {
+ id: lineItem
+ width: recordingsList.width
+ property bool isPlaying : vocalPlayer.item && vocalPlayer.item.playbackState === SoundPlayer.PlayingState
+ onIsPlayingChanged: {
+ if (isPlaying) {
+ if(mediaProgressBar.value >= 100)
+ mediaProgressBar.value = 0
+ timer.start()
+ } else {
+ timer.stop()
+ }
+ }
+ Loader{
+ id: vocalPlayer
+ active: false
+ sourceComponent: SoundPlayer {
+ id: player
+ source: $modelData.filePath
+ onStopped: {
+ mediaProgressBar.value = 101
+ videoView.linphonePlayer = null
+ }
+ Component.onCompleted: {
+ mediaProgressBar.value = 0
+ play()
+ videoView.linphonePlayer = null
+ if( player.hasVideo())
+ videoView.linphonePlayer = player
+ }
+ }
+ }
+ ActionButton {
+ Layout.alignment: Qt.AlignRight
+ isCustom: true
+ colorSet: lineItem.isPlaying ? RecordingsStyle.buttons.pause : RecordingsStyle.buttons.play
+ onClicked: {
+ if(!vocalPlayer.active)
+ vocalPlayer.active = true
+ else if(lineItem.isPlaying){// Pause the play
+ vocalPlayer.item.pause()
+ }else{// Play the audio
+ vocalPlayer.item.play()
+ videoView.linphonePlayer = null
+ if(vocalPlayer.item.hasVideo())
+ videoView.linphonePlayer = vocalPlayer.item
+ }
+ }
+ }
+ ColumnLayout {
+ Layout.rightMargin : 15
+ Layout.leftMargin : 30
+ Layout.fillWidth: true
+ spacing:0
+ RowLayout {
+ Layout.fillWidth: true
+ Layout.topMargin: 10
+ Text {
+ Layout.fillWidth: true
+ Layout.alignment: Qt.AlignLeft
+ text: lineLoader.title
+ horizontalAlignment: Text.AlignLeft
+ font.pointSize: RecordingsStyle.filename.pointSize
+ color: RecordingsStyle.filename.color
+ }
+ Text {
+ id: durationText
+ Layout.fillWidth: true
+ Layout.alignment: Qt.AlignRight
+ text: (vocalPlayer.item ? Utils.formatElapsedTime(vocalPlayer.item.getPosition()/1000) + "/" : '')
+ +Utils.formatElapsedTime($modelData.duration/1000)
+ horizontalAlignment: Text.AlignRight
+ font.pointSize: RecordingsStyle.filename.pointSize
+ color: RecordingsStyle.filename.color
+ }
+ }
+ Slider {
+ id: mediaProgressBar
+ Layout.fillWidth: true
+ Layout.leftMargin: 20
+ enabled: true
+ to: 101
+ value: vocalPlayer.item ? 0.01 * progressDuration / 5 : 0
+ Timer{
+ id: timer
+ repeat: true
+ onTriggered: {
+ if( vocalPlayer.item){
+ mediaProgressBar.value = 100 * ( vocalPlayer.item.getPosition() / vocalPlayer.item.duration)
+ durationText.text = Utils.formatElapsedTime(vocalPlayer.item.getPosition()/1000) + "/" + Utils.formatElapsedTime(vocalPlayer.item.duration/1000)
+ }
+ }
+ interval: 5
+ }
+ onValueChanged:{
+ if(value > 100){
+ timer.stop()
+ durationText.text = Utils.formatElapsedTime(0) + "/" + Utils.formatElapsedTime(vocalPlayer.item.duration/1000)
+ if(vocalPlayer.item)
+ vocalPlayer.item.stop()
+ value = 0
+ }
+ }
+ onMoved: if(vocalPlayer.item){
+ vocalPlayer.item.seek(vocalPlayer.item.duration*value / 100)
+ value = 100 * (vocalPlayer.item.getPosition() / vocalPlayer.item.duration)
+ }
+ }
+ }
+
+ ActionButton {
+ Layout.rightMargin : 30
+ Layout.leftMargin : 15
+ isCustom: true
+ backgroundRadius: width/2
+ colorSet: RecordingsStyle.buttons.remove
+ onClicked: {
+ window.detachVirtualWindow()
+ window.attachVirtualWindow(Utils.buildCommonDialogUri('ConfirmDialog'), {
+ //: 'Are you sure you want to delete this item?' : Confirmation message for removing a record.
+ descriptionText: qsTr('recordingsDelete'),
+ }, function (status) {
+ if (status) {
+ recordingsProxyModel.remove($modelData)
+ }
+ })
+
+ }
+ }
+ }
+ }
+//--------------------------------------------------------------------------
+// FILE
+//--------------------------------------------------------------------------
+ Component{
+ id: fileComponent
+ RowLayout{
+ width: recordingsList.width
+ Item{
+ height: RecordingsStyle.buttons.size
+ width: height
+ ActionButton{
+ anchors.centerIn: parent
+ isCustom: true
+ backgroundRadius: width/2
+ colorSet: $modelData.type == FileMediaModel.IS_SNAPSHOT ? RecordingsStyle.buttons.openImage : RecordingsStyle.buttons.openFile
+ onClicked: {
+ Qt.openUrlExternally(Utils.getUriFromSystemPath($modelData.filePath))
+ }
+ }
+ }
+ Text{
+ Layout.fillWidth: true
+ Layout.leftMargin : 30
+ text: lineLoader.title
+ font.pointSize: RecordingsStyle.filename.pointSize
+ color: RecordingsStyle.filename.color
+ }
+ ActionButton {
+ Layout.rightMargin : 30
+ Layout.leftMargin : 15
+ isCustom: true
+ backgroundRadius: width/2
+ colorSet: RecordingsStyle.buttons.remove
+ onClicked: {
+ window.detachVirtualWindow()
+ window.attachVirtualWindow(Utils.buildCommonDialogUri('ConfirmDialog'), {
+ //: 'Are you sure you want to delete this item?' : Confirmation message for removing a record.
+ descriptionText: qsTr('recordingsDelete'),
+ }, function (status) {
+ if (status) {
+ recordingsProxyModel.remove($modelData)
+ }
+ })
+
+ }
+ }
+ }
+ }
+ }// Loader
+ }
+ Item{
+ id: videoViewItem
+ anchors.bottom: parent.bottom
+ anchors.horizontalCenter: parent.horizontalCenter
+ height: 200
+ width: height * 16/9
+ visible: videoView.active
+ Loader{
+ id: videoView
+ property SoundPlayer linphonePlayer
+ anchors.fill: parent
+ active: linphonePlayer
+ sourceComponent: Component{
+ CameraView{
+ isPreview: false
+ linphonePlayer: videoView.linphonePlayer
+ }
+ }
+ }
+
+ MovableMouseArea{
+ id: dragger
+ anchors.fill: parent
+ function resetPosition(){
+ videoViewItem.anchors.bottom = mainItem.bottom
+ videoViewItem.anchors.horizontalCenter = mainItem.horizontalCenter
+ }
+ onVisibleChanged: if(!visible){
+ resetPosition()
+ }
+ drag.target: videoViewItem
+ onDraggingChanged: if(dragging){
+ videoViewItem.anchors.bottom = undefined
+ videoViewItem.anchors.horizontalCenter = undefined
+ }
+ onRequestResetPosition: resetPosition()
+ }
+ }
+ }
+}
diff --git a/linphone-app/ui/views/App/Styles/Main/MainWindowStyle.qml b/linphone-app/ui/views/App/Styles/Main/MainWindowStyle.qml
index 655779f01..ef29f8084 100644
--- a/linphone-app/ui/views/App/Styles/Main/MainWindowStyle.qml
+++ b/linphone-app/ui/views/App/Styles/Main/MainWindowStyle.qml
@@ -50,6 +50,12 @@ QtObject {
property color color: ColorsList.add(sectionName+'_me_conferences', 'me_n_b_inv_fg').color
property color selectedColor: ColorsList.add(sectionName+'_me_conferences_c', 'me_p_b_inv_fg').color
}
+ property QtObject recordings: QtObject {
+ property string icon: 'recordings_custom'
+ property int iconSize: 50
+ property color color: ColorsList.add(sectionName+'_me_recordings', 'me_n_b_inv_fg').color
+ property color selectedColor: ColorsList.add(sectionName+'_me_recordings_c', 'me_p_b_inv_fg').color
+ }
/*
property string conferencesIcon: 'conference'
property color conferencesColor: ColorsList.add(sectionName+'_me_confs', 'me_n_b_inv_fg').color
diff --git a/linphone-app/ui/views/App/Styles/Main/RecordingsStyle.qml b/linphone-app/ui/views/App/Styles/Main/RecordingsStyle.qml
new file mode 100644
index 000000000..1e17dbb90
--- /dev/null
+++ b/linphone-app/ui/views/App/Styles/Main/RecordingsStyle.qml
@@ -0,0 +1,80 @@
+pragma Singleton
+import QtQuick 2.7
+
+import Units 1.0
+import ColorsList 1.0
+
+// =============================================================================
+
+QtObject {
+ property string sectionName : 'Recordings'
+
+ property QtObject title: QtObject {
+ property color color: ColorsList.add(sectionName+'_title', 'j').color
+ property int pointSize: Units.dp * 12
+ }
+
+ property QtObject filename: QtObject {
+ property color color: ColorsList.add(sectionName+'_filename', 'j').color
+ property int pointSize: Units.dp * 10
+ }
+
+ property QtObject buttons: QtObject {
+ property int size: 40
+ property QtObject play: QtObject {
+ property int iconSize: buttons.size
+ property string name : 'play'
+ property string icon : 'chat_audio_play_custom'
+ property color backgroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_n', icon, 'ma_n_b_inv_bg').color
+ property color backgroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_h', icon, 'ma_h_b_inv_bg').color
+ property color backgroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_p', icon, 'ma_p_b_inv_bg').color
+ property color foregroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_n', icon, 'ma_n_b_inv_fg').color
+ property color foregroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_h', icon, 'ma_h_b_inv_fg').color
+ property color foregroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_p', icon, 'ma_p_b_inv_fg').color
+ }
+ property QtObject pause: QtObject {
+ property int iconSize: buttons.size
+ property string name : 'pause'
+ property string icon : 'chat_audio_pause_custom'
+ property color backgroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_n', icon, 'ma_n_b_inv_bg').color
+ property color backgroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_h', icon, 'ma_h_b_inv_bg').color
+ property color backgroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_p', icon, 'ma_p_b_inv_bg').color
+ property color foregroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_n', icon, 'ma_n_b_inv_fg').color
+ property color foregroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_h', icon, 'ma_h_b_inv_fg').color
+ property color foregroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_p', icon, 'ma_p_b_inv_fg').color
+ }
+ property QtObject remove: QtObject {
+ property int iconSize: buttons.size
+ 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 openImage: QtObject {
+ property int iconSize: buttons.size/2
+ property string name : 'openImage'
+ property string icon : 'file_unknown_custom'
+ property color backgroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_n', icon, 'ma_n_b_inv_bg').color
+ property color backgroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_h', icon, 'ma_h_b_inv_bg').color
+ property color backgroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_p', icon, 'ma_p_b_inv_bg').color
+ property color foregroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_n', icon, 'ma_n_b_inv_fg').color
+ property color foregroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_h', icon, 'ma_h_b_inv_fg').color
+ property color foregroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_p', icon, 'ma_p_b_inv_fg').color
+ }
+ property QtObject openFile: QtObject {
+ property int iconSize: buttons.size/2
+ property string name : 'openFile'
+ property string icon : 'file_extension_custom'
+ property color backgroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_n', icon, 'ma_n_b_inv_bg').color
+ property color backgroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_h', icon, 'ma_h_b_inv_bg').color
+ property color backgroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_p', icon, 'ma_p_b_inv_bg').color
+ property color foregroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_n', icon, 'ma_n_b_inv_fg').color
+ property color foregroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_h', icon, 'ma_h_b_inv_fg').color
+ property color foregroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_p', icon, 'ma_p_b_inv_fg').color
+ }
+ }
+}
diff --git a/linphone-app/ui/views/App/Styles/qmldir b/linphone-app/ui/views/App/Styles/qmldir
index add72cbbe..d39c67c57 100644
--- a/linphone-app/ui/views/App/Styles/qmldir
+++ b/linphone-app/ui/views/App/Styles/qmldir
@@ -40,6 +40,7 @@ singleton HomeStyle 1.0 Main/HomeStyle.qml
singleton HistoryViewStyle 1.0 Main/HistoryViewStyle.qml
singleton InviteFriendsStyle 1.0 Main/InviteFriendsStyle.qml
singleton MainWindowStyle 1.0 Main/MainWindowStyle.qml
+singleton RecordingsStyle 1.0 Main/RecordingsStyle.qml
singleton AboutStyle 1.0 Main/Dialogs/AboutStyle.qml
singleton AuthenticationRequestStyle 1.0 Main/Dialogs/AuthenticationRequestStyle.qml
diff --git a/linphone-sdk b/linphone-sdk
index e57d22dca..d6c7561ff 160000
--- a/linphone-sdk
+++ b/linphone-sdk
@@ -1 +1 @@
-Subproject commit e57d22dca56af8ecd9b0ee5b8e072dbdd65d2266
+Subproject commit d6c7561ffaecb43bce24e5f34c1a8e023fde6503