diff --git a/.gitmodules b/.gitmodules index a8897ce21..652ee1eaa 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ path = linphone-sdk [submodule "plugins/contacts/contacts-api"] path = plugins/contacts/contacts-api url = https://gitlab.linphone.org/BC/public/linphone-desktop-plugins/contacts/contacts-api.git +[submodule "external/qtkeychain"] + path = external/qtkeychain + url = https://gitlab.linphone.org/BC/public/external/qtkeychain.git \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 7202bd89b..ddba094a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## 5.1.0 - undefined + +### Added +- VFS Encryption +- File viewer in chats (Image/Animated Image/Video/Texts) with the option to export the file. + ## 5.0.2 - 2022-12-13 ### Fixed diff --git a/CMakeLists.txt b/CMakeLists.txt index c5b0cd647..587886e93 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,7 +54,8 @@ set(CMAKE_CXX_STANDARD 11) # Prepare gobal CMAKE configuration specific to the current project set(SDK_BUILD_DIR "${CMAKE_BINARY_DIR}/WORK") # SDK build in WORK. Keep all in it. set(LINPHONE_OUTPUT_DIR "${CMAKE_BINARY_DIR}/linphone-sdk/desktop") - +set(QTKEYCHAIN_OUTPUT_DIR "${CMAKE_BINARY_DIR}/qtkeychain") +set(QTKEYCHAIN_TARGET_NAME "EQt5Keychain") set(APPLICATION_OUTPUT_DIR "${CMAKE_BINARY_DIR}/OUTPUT") set(CMAKE_PREFIX_PATH "${LINPHONE_OUTPUT_DIR};${APPLICATION_OUTPUT_DIR};${APPLICATION_OUTPUT_DIR}/include${PREFIX_PATH}") @@ -65,6 +66,8 @@ elseif(APPLE) else() set( CMAKE_PREFIX_PATH "${CMAKE_PREFIX_PATH};${APPLICATION_OUTPUT_DIR}/${CMAKE_INSTALL_LIBDIR}") endif() +list(APPEND CMAKE_PREFIX_PATH "${QTKEYCHAIN_OUTPUT_DIR}/lib64/cmake") +list(APPEND CMAKE_PREFIX_PATH "${QTKEYCHAIN_OUTPUT_DIR}/lib/cmake") string(REPLACE ";" "|" PREFIX_PATH "${CMAKE_PREFIX_PATH}") #set(PREFIX_PATH "${LINPHONE_OUTPUT_DIR}|${APPLICATION_OUTPUT_DIR}${PREFIX_PATH}") @@ -99,6 +102,7 @@ option(ENABLE_BUILD_EXAMPLES "Enable the build of examples" NO) option(ENABLE_BUILD_VERBOSE "Enable the build generation to be more verbose" NO) option(ENABLE_DAEMON "Enable the linphone daemon interface." NO) option(ENABLE_FFMPEG "Build mediastreamer2 with ffmpeg video support." ON) +option(ENABLE_QT_KEYCHAIN "Build QtKeychain to manage VFS from System key stores." ON) option(ENABLE_SANITIZER "Enable sanitizer." NO) option(ENABLE_STRICT "Build with strict compilator flags e.g. -Wall -Werror" NO) option(ENABLE_TESTS "Build with testing binaries of SDK" NO ) @@ -127,6 +131,9 @@ endif() option(ENABLE_RELATIVE_PREFIX "Set Internal packages relative to the binary" YES) +#QtKeychain +option(LIBSECRET_SUPPORT "Build with libsecret support" OFF) #Need libsecret-devel + set(APP_OPTIONS "-DENABLE_UPDATE_CHECK=${ENABLE_UPDATE_CHECK}") list(APPEND APP_OPTIONS "-DENABLE_APP_LICENSE=${ENABLE_APP_LICENSE}") list(APPEND APP_OPTIONS "-DENABLE_APP_PACKAGING=${ENABLE_APP_PACKAGING}") @@ -140,6 +147,7 @@ list(APPEND APP_OPTIONS "-DENABLE_FFMPEG=${ENABLE_FFMPEG}") list(APPEND APP_OPTIONS "-DENABLE_LDAP=${ENABLE_LDAP}") list(APPEND APP_OPTIONS "-DENABLE_NON_FREE_CODECS=${ENABLE_NON_FREE_CODECS}") list(APPEND APP_OPTIONS "-DENABLE_OPENH264=${ENABLE_OPENH264}") +list(APPEND APP_OPTIONS "-DENABLE_QT_KEYCHAIN=${ENABLE_QT_KEYCHAIN}") list(APPEND APP_OPTIONS "-DENABLE_SANITIZER=${ENABLE_SANITIZER}") list(APPEND APP_OPTIONS "-DENABLE_STRICT=${ENABLE_STRICT}") list(APPEND APP_OPTIONS "-DENABLE_TESTS=${ENABLE_TESTS}") @@ -148,9 +156,6 @@ list(APPEND APP_OPTIONS "-DENABLE_TOOLS=${ENABLE_TOOLS}") list(APPEND APP_OPTIONS "-DENABLE_UNIT_TESTS=${ENABLE_UNIT_TESTS}") list(APPEND APP_OPTIONS "-DENABLE_VIDEO=${ENABLE_VIDEO}") - - - if(LINPHONE_SDK_MAKE_RELEASE_FILE_URL) list(APPEND APP_OPTIONS "-DLINPHONE_SDK_MAKE_RELEASE_FILE_URL=${LINPHONE_SDK_MAKE_RELEASE_FILE_URL}") endif() @@ -158,13 +163,15 @@ if(LINPHONESDK_MACOS_ARCHS) list(APPEND APP_OPTIONS "-DLINPHONESDK_MACOS_ARCHS=${LINPHONESDK_MACOS_ARCHS}") endif() - if(ENABLE_V4L) list(APPEND APP_OPTIONS "-DENABLE_V4L=${ENABLE_V4L}") endif() list(APPEND APP_OPTIONS "-DENABLE_RELATIVE_PREFIX=${ENABLE_RELATIVE_PREFIX}") list(APPEND APP_OPTIONS "-DLINPHONE_OUTPUT_DIR=${LINPHONE_OUTPUT_DIR}") +list(APPEND APP_OPTIONS "-DQTKEYCHAIN_OUTPUT_DIR=${QTKEYCHAIN_OUTPUT_DIR}") +list(APPEND APP_OPTIONS "-DQTKEYCHAIN_TARGET_NAME=${QTKEYCHAIN_TARGET_NAME}") + list(APPEND APP_OPTIONS "-DENABLE_QT_GL=${ENABLE_VIDEO}")#Activate on video include(ExternalProject) @@ -192,6 +199,9 @@ if(CMAKE_OSX_DEPLOYMENT_TARGET) endif() list(APPEND APP_OPTIONS "-DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}") +set(QTKEYCHAIN_OPTIONS "-DLIBSECRET_SUPPORT=${LIBSECRET_SUPPORT}") +list(APPEND QTKEYCHAIN_OPTIONS "-DQTKEYCHAIN_TARGET_NAME=${QTKEYCHAIN_TARGET_NAME}") + if(ENABLE_BUILD_APP_PLUGINS) file(GLOB children "plugins/*") set(dirlist "") @@ -209,28 +219,43 @@ endif() if(NOT LINPHONE_QT_ONLY) -ExternalProject_Add(sdk PREFIX "${CMAKE_BINARY_DIR}/sdk" - SOURCE_DIR "${CMAKE_SOURCE_DIR}/linphone-sdk" - INSTALL_DIR "${LINPHONE_OUTPUT_DIR}" - STAMP_DIR "${SDK_BUILD_DIR}/stamp" - BINARY_DIR "${SDK_BUILD_DIR}" - STEP_TARGETS build - BUILD_COMMAND ${CMAKE_COMMAND} --build --config $ ${PROJECT_BUILD_COMMAND} - INSTALL_COMMAND ${CMAKE_COMMAND} -E echo "Install step is already done at build time." - LIST_SEPARATOR | # Use the alternate list separator - CMAKE_ARGS ${APP_OPTIONS} ${USER_ARGS} -DCMAKE_INSTALL_PREFIX:PATH= -DCMAKE_PREFIX_PATH=${PREFIX_PATH} - BUILD_ALWAYS NO #${DO_BUILD} -) -ExternalProject_Add_Step(sdk force_build - COMMENT "Forcing build for 'desktop'" - DEPENDEES configure - DEPENDERS build - ALWAYS 1 -) +#add_subdirectory(external/qtkeychain) + if(ENABLE_QT_KEYCHAIN) + ExternalProject_Add(app-qtkeychain PREFIX "${CMAKE_BINARY_DIR}/qtkeychain" + SOURCE_DIR "${CMAKE_SOURCE_DIR}/external/qtkeychain" + INSTALL_DIR "${QTKEYCHAIN_OUTPUT_DIR}" + BINARY_DIR "${SDK_BUILD_DIR}/qtkeychain" + BUILD_COMMAND ${CMAKE_COMMAND} --build --config $ ${PROJECT_BUILD_COMMAND} + LIST_SEPARATOR | # Use the alternate list separator + CMAKE_ARGS ${APP_OPTIONS} ${QTKEYCHAIN_OPTIONS} ${USER_ARGS} -DCMAKE_INSTALL_PREFIX:PATH= -DCMAKE_PREFIX_PATH=${PREFIX_PATH} + BUILD_ALWAYS NO #${DO_BUILD} + ) + endif() + ExternalProject_Add(sdk PREFIX "${CMAKE_BINARY_DIR}/sdk" + SOURCE_DIR "${CMAKE_SOURCE_DIR}/linphone-sdk" + INSTALL_DIR "${LINPHONE_OUTPUT_DIR}" + STAMP_DIR "${SDK_BUILD_DIR}/stamp" + BINARY_DIR "${SDK_BUILD_DIR}" + STEP_TARGETS build + BUILD_COMMAND ${CMAKE_COMMAND} --build --config $ ${PROJECT_BUILD_COMMAND} + INSTALL_COMMAND ${CMAKE_COMMAND} -E echo "Install step is already done at build time." + LIST_SEPARATOR | # Use the alternate list separator + CMAKE_ARGS ${APP_OPTIONS} ${USER_ARGS} -DCMAKE_INSTALL_PREFIX:PATH= -DCMAKE_PREFIX_PATH=${PREFIX_PATH} + BUILD_ALWAYS NO #${DO_BUILD} + ) + ExternalProject_Add_Step(sdk force_build + COMMENT "Forcing build for 'sdk'" + DEPENDEES configure + DEPENDERS build + ALWAYS 1 + ) endif() include(FindPkgConfig) -set(APP_DEPENDS sdk) +set(APP_DEPENDS sdk)# Used if NOT LINPHONE_QT_ONLY +if(ENABLE_QT_KEYCHAIN) + list(APPEND APP_DEPENDS app-qtkeychain) +endif() find_package(Qt5 5.10 COMPONENTS Core REQUIRED) if ( NOT Qt5_FOUND ) @@ -243,8 +268,12 @@ find_package(bctoolbox CONFIG QUIET) find_package(belcard CONFIG QUIET) find_package(Mediastreamer2 CONFIG QUIET) find_package(ortp CONFIG QUIET) +find_package(${QTKEYCHAIN_TARGET_NAME} CONFIG QUIET) -if(NOT (LinphoneCxx_FOUND) OR NOT (Linphone_FOUND) OR NOT (bctoolbox_FOUND) OR NOT (belcard_FOUND) OR NOT (Mediastreamer2_FOUND) OR NOT (ortp_FOUND) OR FORCE_APP_EXTERNAL_PROJECTS) +if(NOT (LinphoneCxx_FOUND) OR NOT (Linphone_FOUND) OR NOT (bctoolbox_FOUND) OR NOT (belcard_FOUND) OR NOT (Mediastreamer2_FOUND) OR NOT (ortp_FOUND) + OR ( ENABLE_QT_KEYCHAIN AND NOT(${QTKEYCHAIN_TARGET_NAME}_FOUND) ) + OR FORCE_APP_EXTERNAL_PROJECTS +) message("Projects are set as External projects. You can start building them by using for example : cmake --build . --target install") ExternalProject_Add(linphone-qt PREFIX "${CMAKE_BINARY_DIR}/linphone-app" SOURCE_DIR "${CMAKE_SOURCE_DIR}/linphone-app" @@ -270,7 +299,7 @@ if(NOT (LinphoneCxx_FOUND) OR NOT (Linphone_FOUND) OR NOT (bctoolbox_FOUND) OR N CMAKE_ARGS ${APP_OPTIONS} ${USER_ARGS} -DCMAKE_INSTALL_PREFIX:PATH= -DCMAKE_PREFIX_PATH=${PREFIX_PATH} ) endif() - install(CODE "message(STATUS Running install)") + install(CODE "message(STATUS \"Running install\")") set(AUTO_REGENERATION auto_regeneration) if( ENABLE_BUILD_APP_PLUGINS) add_custom_target(${AUTO_REGENERATION} ALL diff --git a/external/qtkeychain b/external/qtkeychain new file mode 160000 index 000000000..bb47857ae --- /dev/null +++ b/external/qtkeychain @@ -0,0 +1 @@ +Subproject commit bb47857aed7c3e9a66902ff681680a79f44e81e5 diff --git a/linphone-app/CMakeLists.txt b/linphone-app/CMakeLists.txt index 68475b362..b1c5e7cef 100644 --- a/linphone-app/CMakeLists.txt +++ b/linphone-app/CMakeLists.txt @@ -52,6 +52,11 @@ if(UNIX AND NOT APPLE) endif() list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../cmake") list(APPEND CMAKE_MODULE_PATH "${LINPHONE_OUTPUT_DIR}/cmake") +list(APPEND CMAKE_MODULE_PATH "${LINPHONE_OUTPUT_DIR}/lib64/cmake") +list(APPEND CMAKE_MODULE_PATH "${LINPHONE_OUTPUT_DIR}/lib/cmake") + +list(APPEND CMAKE_PREFIX_PATH "${QTKEYCHAIN_OUTPUT_DIR}/lib64/cmake") +list(APPEND CMAKE_PREFIX_PATH "${QTKEYCHAIN_OUTPUT_DIR}/lib/cmake") set(APP_LIBRARY app-library) set(APP_PLUGIN app-plugin) @@ -82,6 +87,10 @@ find_package(belcard CONFIG) find_package(Mediastreamer2 CONFIG) find_package(ortp CONFIG) +if(ENABLE_QT_KEYCHAIN) + find_package(${QTKEYCHAIN_TARGET_NAME} CONFIG REQUIRED) +endif() + if(ENABLE_BUILD_VERBOSE) message("INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX} FRAMEWORK_PATH=${CMAKE_FRAMEWORK_PATH}, PREFIX_PATH=${CMAKE_PREFIX_PATH}") message("LINPHONE : ${LINPHONE_INCLUDE_DIRS} => ${LINPHONE_LIBRARIES}") @@ -204,6 +213,7 @@ set(SOURCES src/components/core/event-count-notifier/AbstractEventCountNotifier.cpp src/components/file/FileDownloader.cpp src/components/file/FileExtractor.cpp + src/components/file/TemporaryFile.cpp src/components/friend/FriendListListener.cpp src/components/history/HistoryModel.cpp src/components/history/HistoryProxyModel.cpp @@ -340,6 +350,7 @@ set(HEADERS src/components/core/event-count-notifier/AbstractEventCountNotifier.hpp src/components/file/FileDownloader.hpp src/components/file/FileExtractor.hpp + src/components/file/TemporaryFile.hpp src/components/friend/FriendListListener.hpp src/components/history/HistoryModel.hpp src/components/history/HistoryProxyModel.hpp @@ -452,6 +463,11 @@ else () ) endif () +if(ENABLE_QT_KEYCHAIN) + list(APPEND HEADERS src/components/vfs/VfsUtils.hpp) + list(APPEND SOURCES src/components/vfs/VfsUtils.cpp) +endif() + set(QRC_RESOURCES resources.qrc) if(ENABLE_APP_WEBVIEW) set(QRC_WEBVIEW_RESOURCES webview_resources.qrc) @@ -614,6 +630,12 @@ set(INCLUDED_DIRECTORIES "${LINPHONECXX_INCLUDE_DIRS}" "${MEDIASTREAMER2_INCLUDE list(APPEND INCLUDED_DIRECTORIES "${CMAKE_INSTALL_PREFIX}/include") set(LIBRARIES_LIST ${BCTOOLBOX_CORE_LIBRARIES} ${BELCARD_LIBRARIES} ${LINPHONE_LIBRARIES} ${LINPHONECXX_LIBRARIES} ${MEDIASTREAMER2_LIBRARIES} ${ORTP_LIBRARIES} ${OPUS_LIBRARIES}) + +#if(ENABLE_QT_KEYCHAIN) +# list(APPEND INCLUDED_DIRECTORIES ${QtKeyChain_INCLUDE_DIRS}) +# list(APPEND LIBRARIES_LIST ${QtKeyChain_LIBRARIES}) +#endif() + if(WIN32) set(LIBRARIES) foreach(LIBRARY ${LIBRARIES_LIST})# Search for lib full path @@ -656,6 +678,12 @@ foreach (package ${QT5_PACKAGES_OPTIONAL}) endif () endforeach () +if(ENABLE_QT_KEYCHAIN) + target_link_libraries(${APP_LIBRARY} ${QTKEYCHAIN_TARGET_NAME}) + target_link_libraries(${APP_PLUGIN} ${QTKEYCHAIN_TARGET_NAME}) + target_link_libraries(${TARGET_NAME} ${QTKEYCHAIN_TARGET_NAME}) +endif() + if (APPLE) list(APPEND LIBRARIES "-framework Cocoa -framework IOKit -framework AVFoundation") diff --git a/linphone-app/assets/languages/da.ts b/linphone-app/assets/languages/da.ts index ef140d3c4..402a804a2 100644 --- a/linphone-app/assets/languages/da.ts +++ b/linphone-app/assets/languages/da.ts @@ -1366,6 +1366,14 @@ Server url ikke konfigureret. + + FileViewDialog + + exportAsTitle + "Export As...": Title of a file dialog to export a file. + + + HistoryView @@ -2356,6 +2364,44 @@ Klik her: <a href="%1">%1</a> viewlogs + + vfsTitle + 'VFS' + + + + vfsEncryption + 'Encrypt all the application' : Label to encrypt application + + + + vfsDeactivation + 'Are you sure to deactivate the encryption? The application will exit and all your data will be lost. You must delete them before using the application.' : Explanation to deactivate the VFS encryption. + + + + vfsActivation + 'Are you sure to activate the encryption? You cannot revert without deleting ALL your data' : Explanation to activate the VFS encryption. + + + + cancel + ANNULLER + + + deleteData + 'Delete data' : Action to delete all data. + + + + confirm + + + + vfsDeletion + 'The application will delete your application data files. Do you confirm ?' + + SettingsAudio @@ -3669,6 +3715,21 @@ Klik her: <a href="%1">%1</a> + + VfsUtils + + Delete key failed: %1 + + + + Read key failed: %1 + + + + Write key failed: %1 + + + WaitingRoom diff --git a/linphone-app/assets/languages/de.ts b/linphone-app/assets/languages/de.ts index 6f1afde05..e2114e757 100644 --- a/linphone-app/assets/languages/de.ts +++ b/linphone-app/assets/languages/de.ts @@ -580,7 +580,7 @@ Server URL ist nicht konfiguriert. icsDescription 'Description' : Title for the meeting description. - + Beschreibung icsJoinButton @@ -1366,6 +1366,14 @@ Server URL ist nicht konfiguriert. + + FileViewDialog + + exportAsTitle + "Export As...": Title of a file dialog to export a file. + + + HistoryView @@ -2356,6 +2364,44 @@ Klicken Sie hier: <a href="%1">%1</a> viewlogs + + vfsTitle + 'VFS' + + + + vfsEncryption + 'Encrypt all the application' : Label to encrypt application + + + + vfsDeactivation + 'Are you sure to deactivate the encryption? The application will exit and all your data will be lost. You must delete them before using the application.' : Explanation to deactivate the VFS encryption. + + + + vfsActivation + 'Are you sure to activate the encryption? You cannot revert without deleting ALL your data' : Explanation to activate the VFS encryption. + + + + cancel + + + + deleteData + 'Delete data' : Action to delete all data. + + + + confirm + + + + vfsDeletion + 'The application will delete your application data files. Do you confirm ?' + + SettingsAudio @@ -3669,6 +3715,21 @@ Klicken Sie hier: <a href="%1">%1</a> + + VfsUtils + + Delete key failed: %1 + + + + Read key failed: %1 + + + + Write key failed: %1 + + + WaitingRoom diff --git a/linphone-app/assets/languages/en.ts b/linphone-app/assets/languages/en.ts index 5f69dff3a..c868a41c3 100644 --- a/linphone-app/assets/languages/en.ts +++ b/linphone-app/assets/languages/en.ts @@ -1366,6 +1366,14 @@ Server URL not configured. In your app go in assistant - QR code provisioning + + FileViewDialog + + exportAsTitle + "Export As...": Title of a file dialog to export a file. + Export As… + + HistoryView @@ -2356,6 +2364,44 @@ Click here: <a href="%1">%1</a> viewlogs VIEW + + vfsTitle + 'VFS' + VFS + + + vfsEncryption + 'Encrypt all the application' : Label to encrypt application + Encrypt all the application + + + vfsDeactivation + 'Are you sure to deactivate the encryption? The application will exit and all your data will be lost. You must delete them before using the application.' : Explanation to deactivate the VFS encryption. + Are you sure to deactivate the encryption? The application will exit and all your data will be lost. You must delete them before using the application. + + + vfsActivation + 'Are you sure to activate the encryption? You cannot revert without deleting ALL your data' : Explanation to activate the VFS encryption. + Are you sure to activate the encryption? You cannot revert without deleting ALL your data. + + + cancel + Cancel + + + confirm + Confirm + + + vfsDeletion + 'The application will delete your application data files. Do you confirm ?' + The application will delete your application data files. Do you confirm ? + + + deleteData + 'Delete data' : Action to delete all data. + Delete data + SettingsAudio @@ -3692,6 +3738,21 @@ Click here: <a href="%1">%1</a> To enable it in a commercial project, please contact us. + + VfsUtils + + Delete key failed: %1 + Delete key failed: %1 + + + Read key failed: %1 + Read key failed: %1 + + + Write key failed: %1 + Write key failed: %1 + + WaitingRoom diff --git a/linphone-app/assets/languages/es.ts b/linphone-app/assets/languages/es.ts index 039bd89a1..328d44ddc 100644 --- a/linphone-app/assets/languages/es.ts +++ b/linphone-app/assets/languages/es.ts @@ -1366,6 +1366,14 @@ URL del servidor no configurada. + + FileViewDialog + + exportAsTitle + "Export As...": Title of a file dialog to export a file. + + + HistoryView @@ -2356,6 +2364,44 @@ Haga clic aquí: <a href="%1">%1 </a> viewlogs + + vfsTitle + 'VFS' + + + + vfsEncryption + 'Encrypt all the application' : Label to encrypt application + + + + vfsDeactivation + 'Are you sure to deactivate the encryption? The application will exit and all your data will be lost. You must delete them before using the application.' : Explanation to deactivate the VFS encryption. + + + + vfsActivation + 'Are you sure to activate the encryption? You cannot revert without deleting ALL your data' : Explanation to activate the VFS encryption. + + + + cancel + CANCELAR + + + deleteData + 'Delete data' : Action to delete all data. + + + + confirm + + + + vfsDeletion + 'The application will delete your application data files. Do you confirm ?' + + SettingsAudio @@ -3669,6 +3715,21 @@ Haga clic aquí: <a href="%1">%1 </a> + + VfsUtils + + Delete key failed: %1 + + + + Read key failed: %1 + + + + Write key failed: %1 + + + WaitingRoom diff --git a/linphone-app/assets/languages/fr_FR.ts b/linphone-app/assets/languages/fr_FR.ts index 1360155b1..c9df3b6b1 100644 --- a/linphone-app/assets/languages/fr_FR.ts +++ b/linphone-app/assets/languages/fr_FR.ts @@ -173,7 +173,7 @@ usernameStatusInvalidCharacters - Caractères invalides détectés (regex : `%1`). + Caractères invalides détectés (regex : `%1`). usernameStatusInvalid @@ -189,7 +189,7 @@ passwordStatusInvalidCharacters - Caractères invalides détectés (regex : `%1`). + Caractères invalides détectés (regex : `%1`). passwordStatusMissingCharacters @@ -1241,7 +1241,7 @@ URL du serveur non configurée. ephemeralNotInConference! 'Ephemeral message is only supported in conference based chat room!' - Les messages éphémères ne sont disponibles que pour une conversation définie en mode conférence ! + Les messages éphémères ne sont disponibles que pour une conversation définie en mode conférence ! Warning about not being in conference based chat room. @@ -1366,6 +1366,14 @@ URL du serveur non configurée. Allez dans l'assistant de l'application - QR code + + FileViewDialog + + exportAsTitle + "Export As...": Title of a file dialog to export a file. + + + HistoryView @@ -2025,7 +2033,7 @@ Cliquez ici : <a href="%1">%1</a> newConferenceScheduleTitle 'Would you like to schedule your meeting?' : Ask about setting the meeting as scheduled. - Voulez-vous programmer cette réunion ? + Voulez-vous programmer cette réunion ? newConferenceDate @@ -2356,6 +2364,44 @@ Cliquez ici : <a href="%1">%1</a> viewlogs AFFICHER + + vfsTitle + 'VFS' + + + + vfsEncryption + 'Encrypt all the application' : Label to encrypt application + + + + vfsDeactivation + 'Are you sure to deactivate the encryption? The application will exit and all your data will be lost. You must delete them before using the application.' : Explanation to deactivate the VFS encryption. + + + + vfsActivation + 'Are you sure to activate the encryption? You cannot revert without deleting ALL your data' : Explanation to activate the VFS encryption. + + + + cancel + + + + deleteData + 'Delete data' : Action to delete all data. + + + + confirm + + + + vfsDeletion + 'The application will delete your application data files. Do you confirm ?' + + SettingsAudio @@ -2605,7 +2651,7 @@ Cliquez ici : <a href="%1">%1</a> serverTooltip - Serveur LDAP. ie : ldap:// pour un serveur local ou ldap://ldap.example.org/ + Serveur LDAP. ie : ldap:// pour un serveur local ou ldap://ldap.example.org/ bindDNLabel @@ -3551,7 +3597,7 @@ Cliquez ici : <a href="%1">%1</a> deleteTimeline 'Are you sure you want to delete and leave this timeline?' - Êtes-vous certain de vouloir tout effacer et de quitter cette conversation ? + Êtes-vous certain de vouloir tout effacer et de quitter cette conversation ? deleteTimelineTooltip @@ -3669,6 +3715,21 @@ Cliquez ici : <a href="%1">%1</a> Si vous souhaitez les activer pour un projet professionnel, contactez-nous. + + VfsUtils + + Delete key failed: %1 + + + + Read key failed: %1 + + + + Write key failed: %1 + + + WaitingRoom diff --git a/linphone-app/assets/languages/hu.ts b/linphone-app/assets/languages/hu.ts index ce392ee15..f70b89b1a 100644 --- a/linphone-app/assets/languages/hu.ts +++ b/linphone-app/assets/languages/hu.ts @@ -1356,6 +1356,14 @@ A kiszolgáló URL-je nincs konfigurálva. + + FileViewDialog + + exportAsTitle + "Export As...": Title of a file dialog to export a file. + + + HistoryView @@ -2343,6 +2351,44 @@ Kattintson ide: <a href="%1">%1</a> viewlogs + + vfsTitle + 'VFS' + + + + vfsEncryption + 'Encrypt all the application' : Label to encrypt application + + + + vfsDeactivation + 'Are you sure to deactivate the encryption? The application will exit and all your data will be lost. You must delete them before using the application.' : Explanation to deactivate the VFS encryption. + + + + vfsActivation + 'Are you sure to activate the encryption? You cannot revert without deleting ALL your data' : Explanation to activate the VFS encryption. + + + + cancel + Mégse + + + deleteData + 'Delete data' : Action to delete all data. + + + + confirm + + + + vfsDeletion + 'The application will delete your application data files. Do you confirm ?' + + SettingsAudio @@ -3656,6 +3702,21 @@ Kattintson ide: <a href="%1">%1</a> + + VfsUtils + + Delete key failed: %1 + + + + Read key failed: %1 + + + + Write key failed: %1 + + + WaitingRoom diff --git a/linphone-app/assets/languages/it.ts b/linphone-app/assets/languages/it.ts index c4d768163..beb8f4047 100644 --- a/linphone-app/assets/languages/it.ts +++ b/linphone-app/assets/languages/it.ts @@ -1366,6 +1366,14 @@ URL del server non configurato. + + FileViewDialog + + exportAsTitle + "Export As...": Title of a file dialog to export a file. + + + HistoryView @@ -2356,6 +2364,44 @@ Clicca: <a href="%1">%1</a> viewlogs VISTA + + vfsTitle + 'VFS' + + + + vfsEncryption + 'Encrypt all the application' : Label to encrypt application + + + + vfsDeactivation + 'Are you sure to deactivate the encryption? The application will exit and all your data will be lost. You must delete them before using the application.' : Explanation to deactivate the VFS encryption. + + + + vfsActivation + 'Are you sure to activate the encryption? You cannot revert without deleting ALL your data' : Explanation to activate the VFS encryption. + + + + cancel + + + + deleteData + 'Delete data' : Action to delete all data. + + + + confirm + + + + vfsDeletion + 'The application will delete your application data files. Do you confirm ?' + + SettingsAudio @@ -3669,6 +3715,21 @@ Clicca: <a href="%1">%1</a> + + VfsUtils + + Delete key failed: %1 + + + + Read key failed: %1 + + + + Write key failed: %1 + + + WaitingRoom diff --git a/linphone-app/assets/languages/ja.ts b/linphone-app/assets/languages/ja.ts index 557a37a20..7042905df 100644 --- a/linphone-app/assets/languages/ja.ts +++ b/linphone-app/assets/languages/ja.ts @@ -1356,6 +1356,14 @@ + + FileViewDialog + + exportAsTitle + "Export As...": Title of a file dialog to export a file. + + + HistoryView @@ -2343,6 +2351,44 @@ viewlogs + + vfsTitle + 'VFS' + + + + vfsEncryption + 'Encrypt all the application' : Label to encrypt application + + + + vfsDeactivation + 'Are you sure to deactivate the encryption? The application will exit and all your data will be lost. You must delete them before using the application.' : Explanation to deactivate the VFS encryption. + + + + vfsActivation + 'Are you sure to activate the encryption? You cannot revert without deleting ALL your data' : Explanation to activate the VFS encryption. + + + + cancel + キャンセル + + + deleteData + 'Delete data' : Action to delete all data. + + + + confirm + + + + vfsDeletion + 'The application will delete your application data files. Do you confirm ?' + + SettingsAudio @@ -3656,6 +3702,21 @@ + + VfsUtils + + Delete key failed: %1 + + + + Read key failed: %1 + + + + Write key failed: %1 + + + WaitingRoom diff --git a/linphone-app/assets/languages/lt.ts b/linphone-app/assets/languages/lt.ts index 29cb489f1..52213411f 100644 --- a/linphone-app/assets/languages/lt.ts +++ b/linphone-app/assets/languages/lt.ts @@ -1376,6 +1376,14 @@ Nesukonfigūruotas serverio url. + + FileViewDialog + + exportAsTitle + "Export As...": Title of a file dialog to export a file. + + + HistoryView @@ -2369,6 +2377,44 @@ Spustelėkite čia: <a href="%1">%1</a> viewlogs + + vfsTitle + 'VFS' + + + + vfsEncryption + 'Encrypt all the application' : Label to encrypt application + + + + vfsDeactivation + 'Are you sure to deactivate the encryption? The application will exit and all your data will be lost. You must delete them before using the application.' : Explanation to deactivate the VFS encryption. + + + + vfsActivation + 'Are you sure to activate the encryption? You cannot revert without deleting ALL your data' : Explanation to activate the VFS encryption. + + + + cancel + ATSISAKYTI + + + deleteData + 'Delete data' : Action to delete all data. + + + + confirm + + + + vfsDeletion + 'The application will delete your application data files. Do you confirm ?' + + SettingsAudio @@ -3682,6 +3728,21 @@ Spustelėkite čia: <a href="%1">%1</a> + + VfsUtils + + Delete key failed: %1 + + + + Read key failed: %1 + + + + Write key failed: %1 + + + WaitingRoom diff --git a/linphone-app/assets/languages/pt_BR.ts b/linphone-app/assets/languages/pt_BR.ts index aaced721e..5264b10cb 100644 --- a/linphone-app/assets/languages/pt_BR.ts +++ b/linphone-app/assets/languages/pt_BR.ts @@ -1366,6 +1366,14 @@ URL do servidor não configurado. + + FileViewDialog + + exportAsTitle + "Export As...": Title of a file dialog to export a file. + + + HistoryView @@ -2356,6 +2364,44 @@ Clique aqui: <a href="%1">%1 </a> viewlogs + + vfsTitle + 'VFS' + + + + vfsEncryption + 'Encrypt all the application' : Label to encrypt application + + + + vfsDeactivation + 'Are you sure to deactivate the encryption? The application will exit and all your data will be lost. You must delete them before using the application.' : Explanation to deactivate the VFS encryption. + + + + vfsActivation + 'Are you sure to activate the encryption? You cannot revert without deleting ALL your data' : Explanation to activate the VFS encryption. + + + + cancel + + + + deleteData + 'Delete data' : Action to delete all data. + + + + confirm + + + + vfsDeletion + 'The application will delete your application data files. Do you confirm ?' + + SettingsAudio @@ -3669,6 +3715,21 @@ Clique aqui: <a href="%1">%1 </a> + + VfsUtils + + Delete key failed: %1 + + + + Read key failed: %1 + + + + Write key failed: %1 + + + WaitingRoom diff --git a/linphone-app/assets/languages/ru.ts b/linphone-app/assets/languages/ru.ts index 770bd2d14..705d8a5db 100644 --- a/linphone-app/assets/languages/ru.ts +++ b/linphone-app/assets/languages/ru.ts @@ -1376,6 +1376,14 @@ + + FileViewDialog + + exportAsTitle + "Export As...": Title of a file dialog to export a file. + + + HistoryView @@ -2369,6 +2377,44 @@ viewlogs + + vfsTitle + 'VFS' + + + + vfsEncryption + 'Encrypt all the application' : Label to encrypt application + + + + vfsDeactivation + 'Are you sure to deactivate the encryption? The application will exit and all your data will be lost. You must delete them before using the application.' : Explanation to deactivate the VFS encryption. + + + + vfsActivation + 'Are you sure to activate the encryption? You cannot revert without deleting ALL your data' : Explanation to activate the VFS encryption. + + + + cancel + ОТМЕНА + + + deleteData + 'Delete data' : Action to delete all data. + + + + confirm + + + + vfsDeletion + 'The application will delete your application data files. Do you confirm ?' + + SettingsAudio @@ -3682,6 +3728,21 @@ Чтобы включить их в коммерческом проекте, свяжитесь с нами. + + VfsUtils + + Delete key failed: %1 + + + + Read key failed: %1 + + + + Write key failed: %1 + + + WaitingRoom diff --git a/linphone-app/assets/languages/sv.ts b/linphone-app/assets/languages/sv.ts index da6160940..6232a5ae9 100644 --- a/linphone-app/assets/languages/sv.ts +++ b/linphone-app/assets/languages/sv.ts @@ -1366,6 +1366,14 @@ Serverwebbadressen är inte konfigurerad. + + FileViewDialog + + exportAsTitle + "Export As...": Title of a file dialog to export a file. + + + HistoryView @@ -2356,6 +2364,44 @@ Klicka här: <a href="%1">%1</a> viewlogs + + vfsTitle + 'VFS' + + + + vfsEncryption + 'Encrypt all the application' : Label to encrypt application + + + + vfsDeactivation + 'Are you sure to deactivate the encryption? The application will exit and all your data will be lost. You must delete them before using the application.' : Explanation to deactivate the VFS encryption. + + + + vfsActivation + 'Are you sure to activate the encryption? You cannot revert without deleting ALL your data' : Explanation to activate the VFS encryption. + + + + cancel + AVBRYT + + + deleteData + 'Delete data' : Action to delete all data. + + + + confirm + + + + vfsDeletion + 'The application will delete your application data files. Do you confirm ?' + + SettingsAudio @@ -3669,6 +3715,21 @@ Klicka här: <a href="%1">%1</a> + + VfsUtils + + Delete key failed: %1 + + + + Read key failed: %1 + + + + Write key failed: %1 + + + WaitingRoom diff --git a/linphone-app/assets/languages/tr.ts b/linphone-app/assets/languages/tr.ts index 9b6612885..db0ddf732 100644 --- a/linphone-app/assets/languages/tr.ts +++ b/linphone-app/assets/languages/tr.ts @@ -1356,6 +1356,14 @@ Sunucu url'si yapılandırılmadı. + + FileViewDialog + + exportAsTitle + "Export As...": Title of a file dialog to export a file. + + + HistoryView @@ -2343,6 +2351,44 @@ Buraya tıklayın: <a href="%1">%1</a> viewlogs + + vfsTitle + 'VFS' + + + + vfsEncryption + 'Encrypt all the application' : Label to encrypt application + + + + vfsDeactivation + 'Are you sure to deactivate the encryption? The application will exit and all your data will be lost. You must delete them before using the application.' : Explanation to deactivate the VFS encryption. + + + + vfsActivation + 'Are you sure to activate the encryption? You cannot revert without deleting ALL your data' : Explanation to activate the VFS encryption. + + + + cancel + + + + deleteData + 'Delete data' : Action to delete all data. + + + + confirm + + + + vfsDeletion + 'The application will delete your application data files. Do you confirm ?' + + SettingsAudio @@ -3656,6 +3702,21 @@ Buraya tıklayın: <a href="%1">%1</a> Ticari projede etkinleştirmek için lütfen bizimle iletişime geçin. + + VfsUtils + + Delete key failed: %1 + + + + Read key failed: %1 + + + + Write key failed: %1 + + + WaitingRoom diff --git a/linphone-app/assets/languages/uk.ts b/linphone-app/assets/languages/uk.ts index 5f7d0b467..349a85d2f 100644 --- a/linphone-app/assets/languages/uk.ts +++ b/linphone-app/assets/languages/uk.ts @@ -1376,6 +1376,14 @@ + + FileViewDialog + + exportAsTitle + "Export As...": Title of a file dialog to export a file. + + + HistoryView @@ -2369,6 +2377,44 @@ viewlogs + + vfsTitle + 'VFS' + + + + vfsEncryption + 'Encrypt all the application' : Label to encrypt application + + + + vfsDeactivation + 'Are you sure to deactivate the encryption? The application will exit and all your data will be lost. You must delete them before using the application.' : Explanation to deactivate the VFS encryption. + + + + vfsActivation + 'Are you sure to activate the encryption? You cannot revert without deleting ALL your data' : Explanation to activate the VFS encryption. + + + + cancel + СКАСУВАТИ + + + deleteData + 'Delete data' : Action to delete all data. + + + + confirm + + + + vfsDeletion + 'The application will delete your application data files. Do you confirm ?' + + SettingsAudio @@ -3682,6 +3728,21 @@ + + VfsUtils + + Delete key failed: %1 + + + + Read key failed: %1 + + + + Write key failed: %1 + + + WaitingRoom diff --git a/linphone-app/assets/languages/zh_CN.ts b/linphone-app/assets/languages/zh_CN.ts index f715c304e..6beb80eae 100644 --- a/linphone-app/assets/languages/zh_CN.ts +++ b/linphone-app/assets/languages/zh_CN.ts @@ -1356,6 +1356,14 @@ + + FileViewDialog + + exportAsTitle + "Export As...": Title of a file dialog to export a file. + + + HistoryView @@ -2343,6 +2351,44 @@ viewlogs + + vfsTitle + 'VFS' + + + + vfsEncryption + 'Encrypt all the application' : Label to encrypt application + + + + vfsDeactivation + 'Are you sure to deactivate the encryption? The application will exit and all your data will be lost. You must delete them before using the application.' : Explanation to deactivate the VFS encryption. + + + + vfsActivation + 'Are you sure to activate the encryption? You cannot revert without deleting ALL your data' : Explanation to activate the VFS encryption. + + + + cancel + 取消 + + + deleteData + 'Delete data' : Action to delete all data. + + + + confirm + + + + vfsDeletion + 'The application will delete your application data files. Do you confirm ?' + + SettingsAudio @@ -3656,6 +3702,21 @@ + + VfsUtils + + Delete key failed: %1 + + + + Read key failed: %1 + + + + Write key failed: %1 + + + WaitingRoom diff --git a/linphone-app/cmake_builder/linphone_package/CMakeLists.txt b/linphone-app/cmake_builder/linphone_package/CMakeLists.txt index 6c8919489..99e994a83 100644 --- a/linphone-app/cmake_builder/linphone_package/CMakeLists.txt +++ b/linphone-app/cmake_builder/linphone_package/CMakeLists.txt @@ -109,6 +109,10 @@ endif () # ============================================================================== set(APP_QT_CONF_DPI "1") if (WIN32) + if(ENABLE_QT_KEYCHAIN) + file(GLOB LIB_FILES "${QTKEYCHAIN_OUTPUT_DIR}/${CMAKE_INSTALL_BINDIR}/*.dll") + install(FILES ${LIB_FILES} DESTINATION "${CMAKE_INSTALL_BINDIR}/") + endif() file(GLOB LIB_FILES "${LINPHONE_OUTPUT_DIR}/${CMAKE_INSTALL_LIBDIR}/*.dll") install(FILES ${LIB_FILES} DESTINATION "${CMAKE_INSTALL_BINDIR}/") @@ -214,6 +218,10 @@ elseif (APPLE) message("Changing RPATH of ${LIBRARY_FILENAME} from '${LINPHONE_OUTPUT_DIR}/${CMAKE_INSTALL_LIBDIR}' to '@executable_path/../Frameworks'") execute_process(COMMAND install_name_tool -rpath "${LINPHONE_OUTPUT_DIR}/${CMAKE_INSTALL_LIBDIR}" "@executable_path/../Frameworks" "${LIBRARY}") endforeach () + if(ENABLE_QT_KEYCHAIN) + file(GLOB SHARED_LIBRARIES "${QTKEYCHAIN_OUTPUT_DIR}/${CMAKE_INSTALL_LIBDIR}/lib*.dylib") + install(FILES ${SHARED_LIBRARIES} DESTINATION "${APPLICATION_NAME}.app/Contents/Frameworks") + endif() install(TARGETS ${APP_PLUGIN} ARCHIVE DESTINATION "${APPLICATION_NAME}.app/Contents/Frameworks" LIBRARY DESTINATION "${APPLICATION_NAME}.app/Contents/Frameworks" @@ -242,6 +250,9 @@ else()# Not Windows and Apple execute_process(COMMAND install_name_tool -addrpath "$ORIGIN/../lib64" "${LIBRARY}") endforeach () install(DIRECTORY "${LINPHONE_OUTPUT_DIR}/${CMAKE_INSTALL_BINDIR}/" DESTINATION "${CMAKE_INSTALL_BINDIR}" USE_SOURCE_PERMISSIONS) + if(ENABLE_QT_KEYCHAIN) + install(DIRECTORY "${QTKEYCHAIN_OUTPUT_DIR}/${CMAKE_INSTALL_LIBDIR}/" DESTINATION "${CMAKE_INSTALL_LIBDIR}" USE_SOURCE_PERMISSIONS) + endif() #Just in case. This is useless because we have to use CMAKE_INSTALL_LIBDIR if( EXISTS "${LINPHONE_OUTPUT_DIR}/lib/") file(GLOB SHARED_LIBRARIES "${LINPHONE_OUTPUT_DIR}/lib/*.so*") diff --git a/linphone-app/resources.qrc b/linphone-app/resources.qrc index 7ebb4a073..7e027a8fd 100644 --- a/linphone-app/resources.qrc +++ b/linphone-app/resources.qrc @@ -175,6 +175,7 @@ ui/modules/Common/Dialog/DialogDescription.qml ui/modules/Common/Dialog/DialogPlus.qml ui/modules/Common/Dialog/DialogTitle.qml + ui/modules/Common/Dialog/FileViewDialog.qml ui/modules/Common/Form/ActionBar.qml ui/modules/Common/Form/ActionButton.qml ui/modules/Common/Form/ActionSwitch.qml @@ -223,6 +224,7 @@ ui/modules/Common/Form/Tab/TabContainer.qml ui/modules/Common/Form/TransparentTextInput.qml ui/modules/Common/Helpers/DragBox.qml + ui/modules/Common/Helpers/HoveringMouseArea.qml ui/modules/Common/Helpers/InvertedMouseArea.qml ui/modules/Common/Image/Icon.qml ui/modules/Common/Image/RoundedImage.qml @@ -249,6 +251,7 @@ ui/modules/Common/Styles/Animations/BusyIndicatorStyle.qml ui/modules/Common/Styles/Dialog/DateTimeDialogStyle.qml ui/modules/Common/Styles/Dialog/DialogStyle.qml + ui/modules/Common/Styles/Dialog/FileViewDialogStyle.qml ui/modules/Common/Styles/Form/ActionBarStyle.qml ui/modules/Common/Styles/Form/ActionSwitchStyle.qml ui/modules/Common/Styles/Form/Buttons/AbstractTextButtonStyle.qml diff --git a/linphone-app/src/app/App.cpp b/linphone-app/src/app/App.cpp index a03bf65e2..6d700825e 100644 --- a/linphone-app/src/app/App.cpp +++ b/linphone-app/src/app/App.cpp @@ -675,6 +675,7 @@ void App::registerTypes () { registerType("SipAddressesProxyModel"); registerType("SearchSipAddressesModel"); registerType("SearchSipAddressesProxyModel"); + registerType("TemporaryFile"); registerType("TimeZoneProxyModel"); registerType("ColorProxyModel"); diff --git a/linphone-app/src/app/App.hpp b/linphone-app/src/app/App.hpp index 166ba9106..142d1a237 100644 --- a/linphone-app/src/app/App.hpp +++ b/linphone-app/src/app/App.hpp @@ -105,6 +105,7 @@ public: } static constexpr int RestartCode = 1000; + static constexpr int DeleteDataCode = 1001; Q_INVOKABLE void restart () { exit(RestartCode); diff --git a/linphone-app/src/app/main.cpp b/linphone-app/src/app/main.cpp index a6e5b5b40..71eab8f2e 100644 --- a/linphone-app/src/app/main.cpp +++ b/linphone-app/src/app/main.cpp @@ -30,6 +30,9 @@ FILE * gStream = NULL; #endif #include "components/core/CoreManager.hpp" +#include "components/vfs/VfsUtils.hpp" +#include "utils/Utils.hpp" + // ============================================================================= void cleanStream(){ @@ -43,6 +46,7 @@ void cleanStream(){ } + int main (int argc, char *argv[]) { #ifdef __APPLE__ qputenv("QT_ENABLE_GLYPH_CACHE_WORKAROUND", "1"); // On Mac, set this workaround to avoid glitches on M1, because of https://bugreports.qt.io/browse/QTBUG-89379 @@ -53,13 +57,16 @@ int main (int argc, char *argv[]) { freopen_s(&gStream, "CONOUT$", "w", stderr); } #endif + bool vfsEncrypted = VfsUtils::updateSDKWithKey(); + AppController controller(argc, argv); #ifdef QT_QML_DEBUG QQmlDebuggingEnabler enabler; #endif //QLoggingCategory::setFilterRules("*.debug=true;qml=false"); App *app = controller.getApp(); - + if(vfsEncrypted) + qInfo() << "Activation of VFS encryption."; if (app->isSecondary()) { qInfo() << QStringLiteral("Running secondary app success. Kill it now."); @@ -81,5 +88,8 @@ int main (int argc, char *argv[]) { core->stop(); } cleanStream(); + if( ret == App::DeleteDataCode){ + Utils::deleteAllUserDataOffline(); + } return ret; } diff --git a/linphone-app/src/app/providers/ExternalImageProvider.cpp b/linphone-app/src/app/providers/ExternalImageProvider.cpp index 12e33821e..9aeb06f18 100644 --- a/linphone-app/src/app/providers/ExternalImageProvider.cpp +++ b/linphone-app/src/app/providers/ExternalImageProvider.cpp @@ -36,7 +36,7 @@ ExternalImageProvider::ExternalImageProvider () : QQuickImageProvider( } QImage ExternalImageProvider::requestImage (const QString &id, QSize *size, const QSize &) { - QImage image(Utils::getImage(id)); + QImage image(Utils::getImage(QUrl::fromPercentEncoding(id.toUtf8()))); *size = image.size(); return image; } diff --git a/linphone-app/src/components/Components.hpp b/linphone-app/src/components/Components.hpp index 52268068a..3860d98ae 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/TemporaryFile.hpp" #include "history/HistoryProxyModel.hpp" #include "ldap/LdapModel.hpp" #include "ldap/LdapListModel.hpp" diff --git a/linphone-app/src/components/content/ContentModel.cpp b/linphone-app/src/components/content/ContentModel.cpp index 1e16ee65b..c7765cb5d 100644 --- a/linphone-app/src/components/content/ContentModel.cpp +++ b/linphone-app/src/components/content/ContentModel.cpp @@ -294,5 +294,30 @@ void ContentModel::openFile (bool showDirectory) { } } +bool ContentModel::saveAs (const QString& path){ + QString cachePath = Utils::coreStringToAppString(mContent->exportPlainFile()); + bool toDelete = true; + bool result = false; + if(cachePath.isEmpty()) { + cachePath = Utils::coreStringToAppString(mContent->getFilePath()); + toDelete = false; + } + if(!cachePath.isEmpty()) + { + QString decodedPath = QUrl::fromPercentEncoding(path.toUtf8()); + QFile file(cachePath); + QFile newFile(decodedPath); + if(newFile.exists()) + newFile.remove(); + result = file.copy(decodedPath); + if(toDelete) + file.remove(); + if(result) + QDesktopServices::openUrl(QUrl(QStringLiteral("file:///%1").arg(decodedPath))); + } + + return result; +} + void ContentModel::updateTransferData(){ } \ No newline at end of file diff --git a/linphone-app/src/components/content/ContentModel.hpp b/linphone-app/src/components/content/ContentModel.hpp index 7431680a3..21649a7cd 100644 --- a/linphone-app/src/components/content/ContentModel.hpp +++ b/linphone-app/src/components/content/ContentModel.hpp @@ -82,6 +82,7 @@ public: Q_INVOKABLE void downloadFile(); Q_INVOKABLE void cancelDownloadFile(); Q_INVOKABLE void openFile (bool showDirectory = false); + Q_INVOKABLE bool saveAs (const QString& path); QString mThumbnail; diff --git a/linphone-app/src/components/content/ContentProxyModel.cpp b/linphone-app/src/components/content/ContentProxyModel.cpp index f43aecf24..0d140a06d 100644 --- a/linphone-app/src/components/content/ContentProxyModel.cpp +++ b/linphone-app/src/components/content/ContentProxyModel.cpp @@ -56,7 +56,7 @@ void ContentProxyModel::setContentListModel(ContentListModel * model){ void ContentProxyModel::addFile(const QString& path){ ContentListModel* model = qobject_cast(sourceModel()); - model->addFile(path); + model->addFile( QUrl::fromPercentEncoding(path.toUtf8())); } bool ContentProxyModel::filterAcceptsRow ( diff --git a/linphone-app/src/components/file/TemporaryFile.cpp b/linphone-app/src/components/file/TemporaryFile.cpp new file mode 100644 index 000000000..c0db66d2a --- /dev/null +++ b/linphone-app/src/components/file/TemporaryFile.cpp @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2010-2020 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 + +#include "TemporaryFile.hpp" + +#include "components/core/CoreManager.hpp" +#include "components/content/ContentModel.hpp" +#include "components/settings/SettingsModel.hpp" +#include "utils/Utils.hpp" + +// ============================================================================= + +using namespace std; + +TemporaryFile::TemporaryFile (QObject *parent) : QObject(parent) { + +} + +TemporaryFile::~TemporaryFile () { + deleteFile(); +} + +void TemporaryFile::createFileFromContent(ContentModel * contentModel, const bool& exportPlainFile){ + if(contentModel){ + QString filePath; + if( exportPlainFile || CoreManager::getInstance()->getSettingsModel()->getVfsEncrypted() ) + filePath = Utils::coreStringToAppString(contentModel->getContent()->exportPlainFile()); + bool toDelete = true; + if(filePath.isEmpty()){ + filePath = contentModel->getFilePath(); + toDelete = false; + } + setFilePath(filePath, toDelete); + } +} + +QString TemporaryFile::getFilePath () const{ + return mFilePath; +} +void TemporaryFile::setFilePath(const QString& path, const bool& toDelete){ + if(path != mFilePath) { + deleteFile(); + mFilePath = path; + mDeleteFile = toDelete; + emit filePathChanged(); + } +} + +void TemporaryFile::deleteFile(){ + if(mDeleteFile && !mFilePath.isEmpty()) + QFile::remove(mFilePath); + mFilePath = ""; +} + + diff --git a/linphone-app/src/components/file/TemporaryFile.hpp b/linphone-app/src/components/file/TemporaryFile.hpp new file mode 100644 index 000000000..fd790f3b5 --- /dev/null +++ b/linphone-app/src/components/file/TemporaryFile.hpp @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2010-2020 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 TEMPORARY_FILE_H_ +#define TEMPORARY_FILE_H_ + +#include + +// ============================================================================= + +class ContentModel; + +class TemporaryFile : public QObject { + Q_OBJECT +public: + TemporaryFile (QObject *parent = nullptr); + ~TemporaryFile (); + + Q_PROPERTY(QString filePath READ getFilePath NOTIFY filePathChanged)// not changeable from QML as it comes from a ContentModel + + Q_INVOKABLE void createFileFromContent(ContentModel * contentModel, const bool& exportPlainFile = true); + + QString getFilePath () const; + void setFilePath(const QString& path, const bool& toDelete); + + void deleteFile(); + +signals : + void filePathChanged(); + +private: + QString mFilePath; + bool mDeleteFile = false; +}; + +#endif diff --git a/linphone-app/src/components/other/colors/ColorListModel.hpp b/linphone-app/src/components/other/colors/ColorListModel.hpp index e31b99411..5fb0df651 100644 --- a/linphone-app/src/components/other/colors/ColorListModel.hpp +++ b/linphone-app/src/components/other/colors/ColorListModel.hpp @@ -285,7 +285,7 @@ class ColorListModel : public ProxyListModel { // Field error. ADD_COLOR("error", "#FF0000", "Error Generic button.") - + ADD_COLOR_WITH_ALPHA("c", 80, "") ADD_COLOR_WITH_ALPHA("g", 10, "") ADD_COLOR_WITH_ALPHA("g", 20, "") ADD_COLOR_WITH_ALPHA("g", 90, "") diff --git a/linphone-app/src/components/settings/SettingsModel.cpp b/linphone-app/src/components/settings/SettingsModel.cpp index c599ebad6..96dfd3468 100644 --- a/linphone-app/src/components/settings/SettingsModel.cpp +++ b/linphone-app/src/components/settings/SettingsModel.cpp @@ -69,6 +69,38 @@ SettingsModel::SettingsModel (QObject *parent) : QObject(parent) { connect(coreManager->getAccountSettingsModel(), &AccountSettingsModel::accountSettingsUpdated, this, &SettingsModel::videoConferenceEnabledChanged); connect(coreManager->getAccountSettingsModel(), &AccountSettingsModel::accountSettingsUpdated, this, &SettingsModel::secureChatEnabledChanged); + connect(&mVfsUtils, &VfsUtils::keyRead, this, [&](const QString& key, const QString& value){ + if(key == mVfsUtils.getApplicationVfsEncryptionKey()){ + if(!mVfsEncrypted){ + mVfsEncrypted = true; + emit vfsEncryptedChanged(); + } + } + }); + connect(&mVfsUtils, &VfsUtils::keyWritten, this, [&](const QString& key){ + if(key == mVfsUtils.getApplicationVfsEncryptionKey()){ + if(!mVfsEncrypted){ + mVfsEncrypted = true; + emit vfsEncryptedChanged(); + } + } + }); + connect(&mVfsUtils, &VfsUtils::keyDeleted, this, [&](const QString& key){ + if(key == mVfsUtils.getApplicationVfsEncryptionKey()){ + mVfsEncrypted = false; + emit vfsEncryptedChanged(); + if(mVfsUtils.needToDeleteUserData()) + Utils::deleteAllUserData(); + else + App::getInstance()->quit(); + } + }); + + + connect(&mVfsUtils, &VfsUtils::error, this, [&](){ + + }); + configureRlsUri(); } @@ -1697,6 +1729,25 @@ bool SettingsModel::getLogsEnabled (const shared_ptr &config) } // --------------------------------------------------------------------------- + +bool SettingsModel::getVfsEncrypted (){ + mVfsUtils.readKey(mVfsUtils.getApplicationVfsEncryptionKey()); + return mVfsEncrypted; +} + +void SettingsModel::setVfsEncrypted (bool encrypted, const bool deleteUserData){ + if(getVfsEncrypted() != encrypted){ + if(encrypted) { + mVfsUtils.newEncryptionKey(); + }else{// Remove key, stop core, delete data and initiate reboot + mVfsUtils.needToDeleteUserData(deleteUserData); + mVfsUtils.deleteKey(mVfsUtils.getApplicationVfsEncryptionKey()); + } + } +} + +// --------------------------------------------------------------------------- + bool SettingsModel::isDeveloperSettingsAvailable() const { #ifdef DEBUG return true; diff --git a/linphone-app/src/components/settings/SettingsModel.hpp b/linphone-app/src/components/settings/SettingsModel.hpp index ab4211f7f..3ad985b55 100644 --- a/linphone-app/src/components/settings/SettingsModel.hpp +++ b/linphone-app/src/components/settings/SettingsModel.hpp @@ -29,6 +29,7 @@ #include "components/core/CoreHandlers.hpp" #include "components/contacts/ContactsImporterModel.hpp" +#include "components/vfs/VfsUtils.hpp" #include "utils/LinphoneEnums.hpp" // ============================================================================= @@ -221,6 +222,8 @@ class SettingsModel : public QObject { Q_PROPERTY(bool logsEnabled READ getLogsEnabled WRITE setLogsEnabled NOTIFY logsEnabledChanged) Q_PROPERTY(QString logsEmail READ getLogsEmail WRITE setLogsEmail NOTIFY logsEmailChanged) + Q_PROPERTY(bool isVfsEncrypted READ getVfsEncrypted NOTIFY vfsEncryptedChanged) + Q_PROPERTY(bool developerSettingsEnabled READ getDeveloperSettingsEnabled WRITE setDeveloperSettingsEnabled NOTIFY developerSettingsEnabledChanged) Q_PROPERTY(bool isInCall READ getIsInCall NOTIFY isInCallChanged) @@ -610,6 +613,9 @@ public: QString getLogsEmail () const; void setLogsEmail (const QString &email); + bool getVfsEncrypted (); + Q_INVOKABLE void setVfsEncrypted (bool encrypted, const bool deleteUserData); + Q_INVOKABLE bool isLdapAvailable(); // --------------------------------------------------------------------------- @@ -797,6 +803,7 @@ signals: void logsUploadUrlChanged (const QString &url); void logsEnabledChanged (bool status); void logsEmailChanged (const QString &email); + void vfsEncryptedChanged(); void contactImporterChanged(); @@ -808,6 +815,8 @@ private: int mCurrentSettingsTab = 0; MediastreamerUtils::SimpleCaptureGraph *mSimpleCaptureGraph = nullptr; int mCaptureGraphListenerCount = 0; + VfsUtils mVfsUtils; + bool mVfsEncrypted = false; std::shared_ptr mConfig; }; diff --git a/linphone-app/src/components/vfs/VfsUtils.cpp b/linphone-app/src/components/vfs/VfsUtils.cpp new file mode 100644 index 000000000..1ab077002 --- /dev/null +++ b/linphone-app/src/components/vfs/VfsUtils.cpp @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2010-2022 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 "VfsUtils.hpp" + +#include +#include +#include + +#include +#include + +#include +#include + +// ============================================================================= + +VfsUtils::VfsUtils (QObject *parent) : QObject(parent) + , mReadCredentialJob(QLatin1String(APPLICATION_ID)) + , mWriteCredentialJob(QLatin1String(APPLICATION_ID)) + , mDeleteCredentialJob(QLatin1String(APPLICATION_ID)) +{ + mReadCredentialJob.setAutoDelete(false); + mWriteCredentialJob.setAutoDelete(false); + mDeleteCredentialJob.setAutoDelete(false); +} + +void VfsUtils::deleteKey(const QString &key){ + mDeleteCredentialJob.setKey(key); + + QObject::connect(&mDeleteCredentialJob, &QKeychain::DeletePasswordJob::finished, [=](){ + if (mDeleteCredentialJob.error()) { + emit error(tr("Delete key failed: %1").arg(qPrintable(mDeleteCredentialJob.errorString()))); + return; + } + emit keyDeleted(key); + }); + + mDeleteCredentialJob.start(); +} + +void VfsUtils::readKey(const QString &key) { + mReadCredentialJob.setKey(key); + QObject::connect(&mReadCredentialJob, &QKeychain::ReadPasswordJob::finished, [=](){ + if (mReadCredentialJob.error()) { + emit error(tr("Read key failed: %1").arg(qPrintable(mReadCredentialJob.errorString()))); + return; + } + emit keyRead(key, mReadCredentialJob.textData()); + }); + + mReadCredentialJob.start(); +} + +void VfsUtils::writeKey(const QString &key, const QString &value) { + mWriteCredentialJob.setKey(key); + + QObject::connect(&mWriteCredentialJob, &QKeychain::WritePasswordJob::finished, [=](){ + if (mWriteCredentialJob.error()) { + emit error(tr("Write key failed: %1").arg(qPrintable(mWriteCredentialJob.errorString()))); + return; + } + if(key == getApplicationVfsEncryptionKey()) + updateSDKWithKey(value); + emit keyWritten(key); + }); + + mWriteCredentialJob.setTextData(value); + mWriteCredentialJob.start(); +} + +bool VfsUtils::needToDeleteUserData() const{ + return mNeedToDeleteUserData; +} + +void VfsUtils::needToDeleteUserData(const bool& need){ + mNeedToDeleteUserData = need; +} + +//----------------------------------------------------------------------------------------------- + +void VfsUtils::newEncryptionKey(){ + QString value; + bctoolbox::RNG rng; + auto key = rng.randomize(32); + size_t keySize = key.size(); + uint8_t * shaKey = new uint8_t[keySize]; + bctbx_sha256(&key[0], key.size(), keySize, shaKey); + for(int i = 0 ; i < keySize ; ++i) + value += QString::number(shaKey[i], 16); + writeKey(getApplicationVfsEncryptionKey(), value); +} + +bool VfsUtils::updateSDKWithKey() { + int argc = 1; + const char * argv = "dummy"; + QCoreApplication vfsSetter(argc,(char**)&argv); + VfsUtils vfs; + QObject::connect(&vfs, &VfsUtils::keyRead, &vfsSetter, [&vfsSetter, &vfs] (const QString& key, const QString& value){ + VfsUtils::updateSDKWithKey(value); + vfs.mVfsEncrypted = true; + vfsSetter.quit(); + }, Qt::QueuedConnection); + QObject::connect(&vfs, &VfsUtils::error, &vfsSetter, [&vfsSetter](){ + vfsSetter.quit(); + }, Qt::QueuedConnection); + vfs.readKey(vfs.getApplicationVfsEncryptionKey()); + vfsSetter.exec(); + return vfs.mVfsEncrypted; +} + +void VfsUtils::updateSDKWithKey(const QString& key){ + std::string value = Utils::appStringToCoreString(key); + linphone::Factory::get()->setVfsEncryption(LINPHONE_VFS_ENCRYPTION_AES256GCM128_SHA256, (const uint8_t*)value.c_str(), std::min(32, (int)value.length())); +} + +QString VfsUtils::getApplicationVfsEncryptionKey() const{ + return QString(APPLICATION_ID)+"VfsEncryption"; +} \ No newline at end of file diff --git a/linphone-app/src/components/vfs/VfsUtils.hpp b/linphone-app/src/components/vfs/VfsUtils.hpp new file mode 100644 index 000000000..dbf7eb047 --- /dev/null +++ b/linphone-app/src/components/vfs/VfsUtils.hpp @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2010-2022 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 VFS_UTILS_H_ +#define VFS_UTILS_H_ + +#include +#include + +// ============================================================================= + +class VfsUtils : public QObject { + Q_OBJECT + +public: + VfsUtils(QObject *parent = Q_NULLPTR); + + Q_INVOKABLE void deleteKey(const QString& key); // Delete a key and send error() or keyDeleted() + Q_INVOKABLE void readKey(const QString& key); // Read a key, send error() or keyStored() + Q_INVOKABLE void writeKey(const QString& key, const QString& value); // Write a key and send error() or keyWritten() + + + void newEncryptionKey(); // Generate a key, store it and update SDK. + static bool updateSDKWithKey(); // Update SDK if key exists. Return true if encrypted. + static void updateSDKWithKey(const QString& key);// SDK->setVfsEncryption(key) + + QString getApplicationVfsEncryptionKey() const;// Get the key in store keys for VFS encryyption + + bool needToDeleteUserData() const; + void needToDeleteUserData(const bool& need); + +signals: + void keyDeleted(const QString& key); + void keyRead(const QString& key, const QString& value); + void keyWritten(const QString& key); + + void error(const QString& errorText); + +private: + QKeychain::ReadPasswordJob mReadCredentialJob; + QKeychain::WritePasswordJob mWriteCredentialJob; + QKeychain::DeletePasswordJob mDeleteCredentialJob; + + bool mNeedToDeleteUserData = false; + bool mVfsEncrypted = false; +}; + +#endif diff --git a/linphone-app/src/utils/Utils.cpp b/linphone-app/src/utils/Utils.cpp index 5b8cf8025..dc82c3da8 100644 --- a/linphone-app/src/utils/Utils.cpp +++ b/linphone-app/src/utils/Utils.cpp @@ -26,12 +26,14 @@ #include #include #include +#include #include #include #include "config.h" #include "Utils.hpp" #include "UriTools.hpp" +#include "app/App.hpp" #include "components/core/CoreManager.hpp" #include "components/contacts/ContactsListModel.hpp" #include "components/contact/ContactModel.hpp" @@ -566,6 +568,23 @@ bool Utils::isAnimatedImage(const QString& path){ return reader.supportsAnimation() && reader.imageCount() > 1; } +bool Utils::isImage(const QString& path){ + QFileInfo info(path); + if( !info.exists()) + return false; + QImageReader reader(path); + return reader.imageCount() == 1; +} + + +bool Utils::isVideo(const QString& path){ + return QMimeDatabase().mimeTypeForFile(path).name().contains("video"); +} + +bool Utils::isSupportedForDisplay(const QString& path){ + return !QMimeDatabase().mimeTypeForFile(path).name().contains("application");// "for pdf : "application/pdf". Note : Make an exception when supported. +} + bool Utils::isPhoneNumber(const QString& txt){ auto core = CoreManager::getInstance()->getCore(); if(!core) @@ -647,4 +666,30 @@ QString Utils::encodeTextToQmlRichFormat(const QString& text, const QVariantMap& images = "
" + images +"
"; return images + "

" + formattedText.join("") + "

"; +} + +QString Utils::getFileContent(const QString& filePath){ + QString contents; + QFile file(filePath); + if (!file.open(QFile::ReadOnly | QFile::Text)) + return ""; + return file.readAll(); +} +static QStringList gDbPaths; + +void Utils::deleteAllUserData(){ +// Store usable data like custom folders + gDbPaths.clear(); + gDbPaths.append(Utils::coreStringToAppString(linphone::Factory::get()->getDataDir(nullptr))); + gDbPaths.append(Utils::coreStringToAppString(linphone::Factory::get()->getConfigDir(nullptr))); +// Exit with a delete code + App::getInstance()->exit(App::DeleteDataCode); +} + +void Utils::deleteAllUserDataOffline(){ + qWarning() << "Deleting all data! "; + for(int i = 0 ; i < gDbPaths.size() ; ++i){ + QDir dir(gDbPaths[i]); + qWarning() << "Deleting " << gDbPaths[i] << " : " << (dir.removeRecursively() ? "Successfully" : "Failed"); + } } \ No newline at end of file diff --git a/linphone-app/src/utils/Utils.hpp b/linphone-app/src/utils/Utils.hpp index 8c8fcc8b5..1f8437093 100644 --- a/linphone-app/src/utils/Utils.hpp +++ b/linphone-app/src/utils/Utils.hpp @@ -62,11 +62,15 @@ public: Q_INVOKABLE static QString toString(const LinphoneEnums::TunnelMode& mode); Q_INVOKABLE static bool isMe(const QString& address); Q_INVOKABLE static bool isAnimatedImage(const QString& path); + Q_INVOKABLE static bool isImage(const QString& path); + Q_INVOKABLE static bool isVideo(const QString& path); + Q_INVOKABLE static bool isSupportedForDisplay(const QString& path); Q_INVOKABLE static bool isPhoneNumber(const QString& txt); Q_INVOKABLE QSize getImageSize(const QString& url); Q_INVOKABLE static QPoint getCursorPosition(); Q_INVOKABLE static QString getFileChecksum(const QString& filePath); Q_INVOKABLE static QString encodeTextToQmlRichFormat(const QString& text, const QVariantMap& options); + Q_INVOKABLE static QString getFileContent(const QString& filePath); //---------------------------------------------------------------------------------- @@ -146,6 +150,9 @@ public: static bool isMe(const std::shared_ptr& address); + static void deleteAllUserData(); + static void deleteAllUserDataOffline();// When we are out of all events and core is not running (aka in main()) + }; #endif // UTILS_H_ diff --git a/linphone-app/ui/modules/Common/Dialog/ConfirmDialog.qml b/linphone-app/ui/modules/Common/Dialog/ConfirmDialog.qml index f6e7b3a80..676637966 100644 --- a/linphone-app/ui/modules/Common/Dialog/ConfirmDialog.qml +++ b/linphone-app/ui/modules/Common/Dialog/ConfirmDialog.qml @@ -23,11 +23,16 @@ DialogPlus { text: mainItem.buttonTexts[1] visible: mainItem.showButtonOnly<0 || mainItem.showButtonOnly == 1 onClicked: exit(1) + }, + TextButtonB { + text: mainItem.buttonTexts.length > 2 ? mainItem.buttonTexts[2] : '' + visible: mainItem.buttonTexts.length > 2 && (mainItem.showButtonOnly<0 || mainItem.showButtonOnly == 2) + onClicked: exit(2) } ] buttonsAlignment: Qt.AlignCenter height: DialogStyle.confirmDialog.height + 30 - width: DialogStyle.confirmDialog.width + width: Math.max(DialogStyle.confirmDialog.width, buttonTexts.length * 150 + DialogStyle.buttons.leftMargin + DialogStyle.buttons.rightMargin) } diff --git a/linphone-app/ui/modules/Common/Dialog/DialogPlus.qml b/linphone-app/ui/modules/Common/Dialog/DialogPlus.qml index 7c93eb1e6..d27dab5de 100644 --- a/linphone-app/ui/modules/Common/Dialog/DialogPlus.qml +++ b/linphone-app/ui/modules/Common/Dialog/DialogPlus.qml @@ -21,6 +21,7 @@ Rectangle { property bool expandHeight: flat property alias showCloseCross : titleBar.showCloseCross property alias showTitleBar: titleBar.showBar + property alias showButtons: buttonsView.visible property int buttonsLeftMargin :(buttonsAlignment & Qt.AlignLeft )== Qt.AlignLeft ? DialogStyle.buttons.leftMargin diff --git a/linphone-app/ui/modules/Common/Dialog/FileViewDialog.qml b/linphone-app/ui/modules/Common/Dialog/FileViewDialog.qml new file mode 100644 index 000000000..5348da658 --- /dev/null +++ b/linphone-app/ui/modules/Common/Dialog/FileViewDialog.qml @@ -0,0 +1,286 @@ +import QtQuick 2.12 +import QtQuick.Controls 2.15 +import QtQuick.Dialogs 1.2 +import QtQuick.Layouts 1.3 +import QtMultimedia 5.15 + +import Common 1.0 +import Linphone 1.0 +import Utils 1.0 + +import App.Styles 1.0 +import Common.Styles 1.0 +import Linphone.Styles 1.0 + +import UtilsCpp 1.0 + +import 'qrc:/ui/scripts/Utils/utils.js' as Utils + +// ============================================================================= + +DialogPlus{ + id: mainItem + property ContentModel contentModel + property string filePath: tempFile.filePath + property bool isAnimatedImage : filePath && UtilsCpp.isAnimatedImage(filePath) + property bool isVideo: filePath && UtilsCpp.isVideo(filePath) + property bool isImage: filePath && UtilsCpp.isImage(filePath) + property bool isSupportedForDisplay: filePath && UtilsCpp.isSupportedForDisplay(filePath) + + showCloseCross: true + showButtons: !isVideo + buttonsAlignment: Qt.AlignRight + + buttons: [ + ActionButton{ + Layout.preferredHeight: iconSize + Layout.preferredWidth: iconSize + isCustom: true + backgroundRadius: width + colorSet: FileViewDialogStyle.exportFile + onClicked: saveAsDialog.open() + } + ] + + height: window.height - 20 + width: window.width - 20 + expandHeight: true + + radius: 10 + onContentModelChanged: if(contentModel){ + tempFile.createFileFromContent(contentModel, false); + } + onExitStatus: if(loader.sourceComponent == videoComponent) loader.item.stop(); + + TemporaryFile { + id: tempFile + } + + FileDialog { + id: saveAsDialog + folder: shortcuts.documents + //: "Export As...": Title of a file dialog to export a file. + title: qsTr('exportAsTitle') + selectExisting: false + defaultSuffix: Utils.getExtension(mainItem.filePath)// Doesn't seems to work on all platforms + onAccepted: { + var files = fileUrls.reduce(function (files, file) { + if (file.startsWith('file:')) { + files.push(Utils.getSystemPathFromUri(file)) + } + return files + }, []) + contentModel.saveAs(files[0]) + } + } + + Loader{ + id: loader + anchors.fill: parent + + active: true + sourceComponent: isVideo + ? videoComponent + : mainItem.isAnimatedImage + ? animatedImageComponent + : mainItem.isImage + ? imageComponent + : isSupportedForDisplay + ? fileTextComponent + : placeholderComponent +//-------------------------------------------------------------------------------------------------- +// VIDEOS +//-------------------------------------------------------------------------------------------------- + Component{ + id: videoComponent + Video{ + id: videoItem + property bool isPlaying: videoItem.playbackState == MediaPlayer.PlayingState + anchors.fill: parent + source: 'file:'+mainItem.filePath // GStreamer doesn't know 'file://' + autoPlay: true + //loops: MediaPlayer.Infinite// Do not use because MediaPlayer can crash while trying to replay video. + flushMode: VideoOutput.FirstFrame + notifyInterval: 100 + onStatusChanged: { + if(MediaPlayer.EndOfMedia == status){// Workaround for a Qt crash when replaying a video after reaching the End of the Video. + console.info("Closing the popup at the end is a workaround to avoid a crash from Qt(5.15.2)") + mainItem.exit() + } + } + + BusyIndicator{ + visible: videoItem.playbackState == MediaPlayer.StoppedState + anchors.centerIn: parent + height: 50 + width: 50 + color: BusyIndicatorStyle.alternateColor + } + + HoveringMouseArea{ + id: hoveringMouseArea + anchors.fill: parent + acceptedButtons: Qt.LeftButton + cursorShape: Qt.ArrowCursor + onClicked: videoControl.forceVisible = !videoControl.forceVisible + Item{ + id: videoControl + property bool forceVisible: false + property bool autoHide: false + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom + anchors.leftMargin: 20 + anchors.rightMargin: 20 + anchors.bottomMargin: 0 + height: 50 + visible: forceVisible || !videoControl.autoHide || hoveringMouseArea.realRunning + Component.onCompleted: autoHideDelayer.start() + Timer{ + id: autoHideDelayer + interval: 1000 + onTriggered: videoControl.autoHide = true + } + RowLayout{ + anchors.fill: parent + MediaProgressBar{ + id: mediaProgressBar + Layout.fillHeight: true + Layout.fillWidth: true + progressDuration: videoItem.duration + progressPosition: videoItem.position + stopAtEnd: false + resetAtEnd: false + blockValueAtEnd: false + backgroundColor: ChatAudioMessageStyle.backgroundColor + progressLineBackgroundColor: FileViewDialogStyle.progression.backgroundColor + colorSet: FileViewDialogStyle.progression + durationTextColor: ChatStyle.entry.message.outgoing.text.color + progressSize: 10 + customActions: [ + ActionButton{ + Layout.preferredHeight: iconSize + Layout.preferredWidth: iconSize + Layout.leftMargin: 15 + Layout.rightMargin: 5 + isCustom: true + backgroundRadius: width + colorSet: FileViewDialogStyle.exportFile + onClicked: { + if(videoItem.isPlaying) + videoItem.pause() + saveAsDialog.open() + } + }, + ActionButton{ + id: playButton + Layout.preferredHeight: iconSize + Layout.preferredWidth: iconSize + Layout.rightMargin: 5 + Layout.leftMargin: 5 + Layout.alignment: Qt.AlignVCenter + isCustom: true + backgroundRadius: width + colorSet: (videoItem.isPlaying ? FileViewDialogStyle.pauseAction + : FileViewDialogStyle.playAction) + onClicked: videoItem.isPlaying ? videoItem.pause() : videoItem.play() + }, + ActionButton{ + id: muteButton + Layout.preferredHeight: iconSize + Layout.preferredWidth: iconSize + Layout.leftMargin: 5 + Layout.rightMargin: 15 + Layout.alignment: Qt.AlignVCenter + isCustom: true + backgroundRadius: width + colorSet: (videoItem.muted ? FileViewDialogStyle.speakerOff + : FileViewDialogStyle.speakerOn) + onClicked: videoItem.muted = !videoItem.muted + } + ] + onSeekRequested: { + videoItem.seek(ms) + } + } + } + } + } + } + } +//-------------------------------------------------------------------------------------------------- +// ANIMATIONS +//-------------------------------------------------------------------------------------------------- + Component { + id: animatedImageComponent + AnimatedImage { + id: animatedImageSource + property real scaleAnimatorTo : 1.7 + mipmap: SettingsModel.mipmapEnabled + source: 'file:/'+mainItem.filePath + autoTransform: true + fillMode: Image.PreserveAspectFit + } + } +//-------------------------------------------------------------------------------------------------- +// IMAGE +//-------------------------------------------------------------------------------------------------- + Component { + id: imageComponent + Image { + id: imageSource + mipmap: SettingsModel.mipmapEnabled + source: 'file:/'+mainItem.filePath + autoTransform: true + fillMode: Image.PreserveAspectFit + } + } +//-------------------------------------------------------------------------------------------------- +// PLAIN TEXT +//-------------------------------------------------------------------------------------------------- + Component{ + id: fileTextComponent + ListView { + id: idContentListView + model: idContentListView.stringList + anchors.fill: parent + anchors.topMargin: 20 + anchors.leftMargin: 10 + anchors.rightMargin: 10 + + clip: true + + delegate: Text { + width: idContentListView.width + text: model.modelData + font.pointSize: FormTableStyle.entry.text.pointSize + textFormat: Text.PlainText + wrapMode: Text.Wrap + } + ScrollBar.vertical: ScrollBar {} + + property variant stringList: null + function updateText() { + stringList = UtilsCpp.getFileContent(filePath).split('\n') + //idContentListView.positionViewAtEnd() + } + Component.onCompleted: updateText() + } + } +//-------------------------------------------------------------------------------------------------- +// NO DISPLAY +//-------------------------------------------------------------------------------------------------- + Component { + id: placeholderComponent + Icon{ + id: fileIcon + Layout.alignment: Qt.AlignCenter + icon: FileViewDialogStyle.extension.unknownIcon + iconSize: FileViewDialogStyle.extension.iconSize + } + } + } +} + + + diff --git a/linphone-app/ui/modules/Common/Form/DroppableTextArea.qml b/linphone-app/ui/modules/Common/Form/DroppableTextArea.qml index 245149dfb..8770cc78d 100644 --- a/linphone-app/ui/modules/Common/Form/DroppableTextArea.qml +++ b/linphone-app/ui/modules/Common/Form/DroppableTextArea.qml @@ -45,7 +45,6 @@ Item { return files }, []) - if (files.length > 0) { dropped(files) } diff --git a/linphone-app/ui/modules/Common/Helpers/HoveringMouseArea.qml b/linphone-app/ui/modules/Common/Helpers/HoveringMouseArea.qml new file mode 100644 index 000000000..f3933bc18 --- /dev/null +++ b/linphone-app/ui/modules/Common/Helpers/HoveringMouseArea.qml @@ -0,0 +1,43 @@ +import QtQuick 2.7 + +import Common 1.0 +import Utils 1.0 + +import UtilsCpp 1.0 + +MouseArea{ + id: mainItem + property bool realRunning : false + property bool firstUse: true + Timer { + id: hideButtonsTimer + interval: mainItem.firstUse ? 500 : 4000 + running: false + triggeredOnStart: !mainItem.firstUse + onTriggered: {if(!mainItem.firstUse && mainItem.realRunning != running) mainItem.realRunning = running + mainItem.firstUse = false} + function startTimer(){ + if(!mainItem.firstUse || !running) + restart(); + } + function stopTimer(){ + stop() + mainItem.realRunning = false + mainItem.firstUse = false + } + } + + acceptedButtons: Qt.NoButton + propagateComposedEvents: true + cursorShape: undefined + //cursorShape: Qt.ArrowCursor + onEntered: hideButtonsTimer.startTimer() + onExited: { + var cursorPosition = UtilsCpp.getCursorPosition() + mapToItem(window.contentItem, cursorPosition.x, cursorPosition.y) + if (cursorPosition.x <= 0 || cursorPosition.y <= 0 + || cursorPosition.x >= width || cursorPosition.y >= height) + hideButtonsTimer.stopTimer() + } + onPositionChanged: hideButtonsTimer.startTimer() +} \ No newline at end of file diff --git a/linphone-app/ui/modules/Common/Indicators/MediaProgressBar.qml b/linphone-app/ui/modules/Common/Indicators/MediaProgressBar.qml index 89a70b7cc..5e13c5826 100644 --- a/linphone-app/ui/modules/Common/Indicators/MediaProgressBar.qml +++ b/linphone-app/ui/modules/Common/Indicators/MediaProgressBar.qml @@ -14,6 +14,7 @@ import Common.Styles 1.0 ProgressBar { id: progressBar + property alias customActions: customActions.data property bool stopAtEnd: true property bool resetAtEnd: false property int progressDuration // Max duration @@ -21,7 +22,10 @@ ProgressBar { property alias colorSet: progression.colorSet property alias backgroundColor: backgroundArea.color property alias durationTextColor: durationText.color + property alias progressLineBackgroundColor: progressionLineBackground.color property int waveLeftMargin: 0 + property int progressSize: height + property bool blockValueAtEnd: true function start(){ progressBar.value = 0 @@ -45,7 +49,7 @@ ProgressBar { interval: 5 } to: 101 - value: 0 + value: progressPosition * to / progressDuration onValueChanged:{ if(value > 100){ if( progressBar.stopAtEnd) @@ -53,7 +57,7 @@ ProgressBar { if(progressBar.resetAtEnd) { progressBar.value = 0 progressPosition = 0 - }else{ + }else if(progressBar.blockValueAtEnd){ progressBar.value = 100// Stay at 100 progressPosition = progressDuration } @@ -82,19 +86,29 @@ ProgressBar { RowLayout{ anchors.fill: parent spacing: 0 - ActionButton{ - id: progression + RowLayout { + id: customActions + visible: children.length>0 + } + Rectangle{ + id: progressionLineBackground Layout.fillWidth: true - Layout.fillHeight: true Layout.leftMargin: progressBar.waveLeftMargin - backgroundRadius: 5 - fillMode: Image.TileHorizontally - verticalAlignment: Image.AlignLeft - horizontalAlignment: Image.AlignLeft - isCustom: true - colorSet: MediaProgressBarStyle.progressionWave - percentageDisplayed: 0 - onClicked: progressBar.seekRequested(x * progressBar.progressDuration/width) + Layout.preferredHeight: progressBar.progressSize + color: 'transparent' + radius: 5 + ActionButton{ + id: progression + anchors.fill: parent + backgroundRadius: 5 + fillMode: Image.TileHorizontally + verticalAlignment: Image.AlignLeft + horizontalAlignment: Image.AlignLeft + isCustom: true + colorSet: MediaProgressBarStyle.progressionWave + percentageDisplayed: 0 + onClicked: progressBar.seekRequested(x * progressBar.progressDuration/width) + } } Text{ id: durationText diff --git a/linphone-app/ui/modules/Common/Styles/Dialog/FileViewDialogStyle.qml b/linphone-app/ui/modules/Common/Styles/Dialog/FileViewDialogStyle.qml new file mode 100644 index 000000000..a553c690e --- /dev/null +++ b/linphone-app/ui/modules/Common/Styles/Dialog/FileViewDialogStyle.qml @@ -0,0 +1,109 @@ +pragma Singleton +import QtQml 2.2 + +import Units 1.0 +import ColorsList 1.0 + +// ============================================================================= + +QtObject { + property string sectionName : 'FileView' + + property QtObject progression: QtObject{ + property int iconSize: 60 + property int iconHeight: 60 + property int iconWidth: 60 + property string name : 'progression' + property string icon : '' + + property color backgroundColor: ColorsList.addImageColor(sectionName+'_'+name+'_bg', icon, 'c80').color + + property color backgroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_n', icon, 'w_n_b_bg').color + property color backgroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_h', icon, 'w_h_b_bg').color + property color backgroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_p', icon, 'w_p_b_bg').color + property color foregroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_n', icon, 'w_n_b_fg').color + property color foregroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_h', icon, 'w_h_b_fg').color + property color foregroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_p', icon, 'w_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 pauseAction: QtObject { + property int iconSize: 25 + property string name : 'pause' + property string icon : 'chat_audio_pause_custom' + property color backgroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_n', icon, 's_h_b_bg').color + property color backgroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_h', icon, 's_n_b_bg').color + property color backgroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_p', icon, 's_p_b_bg').color + property color backgroundDisabledColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_d', icon, 's_d_b_bg').color + property color foregroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_n', icon, 's_h_b_fg').color + property color foregroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_h', icon, 's_n_b_fg').color + property color foregroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_p', icon, 's_p_b_fg').color + property color foregroundDisabledColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_d', icon, 's_d_b_fg').color + } + property QtObject playAction: QtObject { + property int iconSize: 25 + property string name : 'play' + property string icon : 'chat_audio_play_custom' + property color backgroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_n', icon, 's_h_b_bg').color + property color backgroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_h', icon, 's_n_b_bg').color + property color backgroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_p', icon, 's_p_b_bg').color + property color backgroundDisabledColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_d', icon, 's_d_b_bg').color + property color foregroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_n', icon, 's_h_b_fg').color + property color foregroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_h', icon, 's_n_b_fg').color + property color foregroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_p', icon, 's_p_b_fg').color + property color foregroundDisabledColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_d', icon, 's_d_b_fg').color + } + + property QtObject speakerOn: QtObject { + property int iconSize: 25 + property string icon : 'speaker_on_custom' + property string name : 'speakerOn' + property color backgroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_n', icon, 's_h_b_bg').color + property color backgroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_h', icon, 's_n_b_bg').color + property color backgroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_p', icon, 's_p_b_bg').color + property color backgroundDisabledColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_d', icon, 's_d_b_bg').color + property color foregroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_n', icon, 's_h_b_fg').color + property color foregroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_h', icon, 's_n_b_fg').color + property color foregroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_p', icon, 's_p_b_fg').color + property color foregroundDisabledColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_d', icon, 's_d_b_fg').color + } + property QtObject speakerOff: QtObject { + property int iconSize: 25 + property string icon : 'speaker_off_custom' + property string name : 'speakerOff' + property color backgroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_n', icon, 's_h_b_bg').color + property color backgroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_h', icon, 's_n_b_bg').color + property color backgroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_p', icon, 's_p_b_bg').color + property color backgroundDisabledColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_d', icon, 's_d_b_bg').color + property color foregroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_n', icon, 's_h_b_fg').color + property color foregroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_h', icon, 's_n_b_fg').color + property color foregroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_p', icon, 's_p_b_fg').color + property color foregroundDisabledColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_d', icon, 's_d_b_fg').color + } + property QtObject exportFile: QtObject{ + property string icon: 'download_custom' + property string name : 'exportFile' + property int height: 20 + property int pointSize: Units.dp * 8 + property int iconSize: 25 + property color backgroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_n', icon, 's_h_b_bg').color + property color backgroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_h', icon, 's_n_b_bg').color + property color backgroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_p', icon, 's_p_b_bg').color + property color backgroundDisabledColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_d', icon, 's_d_b_bg').color + property color foregroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_n', icon, 's_h_b_fg').color + property color foregroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_h', icon, 's_n_b_fg').color + property color foregroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_p', icon, 's_p_b_fg').color + property color foregroundDisabledColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_d', icon, 's_d_b_fg').color + } + property QtObject extension: QtObject { + property string unknownIcon: 'file_unknown_custom' + property int iconSize: 60 + } +} \ No newline at end of file diff --git a/linphone-app/ui/modules/Common/Styles/qmldir b/linphone-app/ui/modules/Common/Styles/qmldir index d76b12f3d..58e9ee5ff 100644 --- a/linphone-app/ui/modules/Common/Styles/qmldir +++ b/linphone-app/ui/modules/Common/Styles/qmldir @@ -8,6 +8,7 @@ singleton BusyIndicatorStyle 1.0 Animations/BusyIndicatorStyle.qml singleton DialogStyle 1.0 Dialog/DialogStyle.qml singleton DateTimeDialogStyle 1.0 Dialog/DateTimeDialogStyle.qml +singleton FileViewDialogStyle 1.0 Dialog/FileViewDialogStyle.qml singleton ActionBarStyle 1.0 Form/ActionBarStyle.qml singleton ActionSwitchStyle 1.0 Form/ActionSwitchStyle.qml diff --git a/linphone-app/ui/modules/Common/qmldir b/linphone-app/ui/modules/Common/qmldir index a025a39b3..bb160d06c 100644 --- a/linphone-app/ui/modules/Common/qmldir +++ b/linphone-app/ui/modules/Common/qmldir @@ -16,6 +16,8 @@ DateTimeDialog 1.0 Dialog/DateTimeDialog.qml DialogDescription 1.0 Dialog/DialogDescription.qml ConfirmDialog 1.0 Dialog/ConfirmDialog.qml DialogPlus 1.0 Dialog/DialogPlus.qml +FileViewDialog 1.0 Dialog/FileViewDialog.qml + ActionBar 1.0 Form/ActionBar.qml ActionButton 1.0 Form/ActionButton.qml @@ -65,6 +67,7 @@ TabButton 1.0 Form/Tab/TabButton.qml TabContainer 1.0 Form/Tab/TabContainer.qml DragBox 1.0 Helpers/DragBox.qml +HoveringMouseArea 1.0 Helpers/HoveringMouseArea.qml InvertedMouseArea 1.0 Helpers/InvertedMouseArea.qml Icon 1.0 Image/Icon.qml diff --git a/linphone-app/ui/modules/Linphone/Chat/ChatAudioMessage.qml b/linphone-app/ui/modules/Linphone/Chat/ChatAudioMessage.qml index 50c8ebfdf..79eae26ab 100644 --- a/linphone-app/ui/modules/Linphone/Chat/ChatAudioMessage.qml +++ b/linphone-app/ui/modules/Linphone/Chat/ChatAudioMessage.qml @@ -32,8 +32,18 @@ Loader{ property bool isOutgoing : contentModel && contentModel.chatMessageModel && (contentModel.chatMessageModel.isOutgoing || contentModel.chatMessageModel.state == LinphoneEnums.ChatMessageStateIdle); property bool isActive: active + property string filePath : tempFile.filePath + active: contentModel && contentModel.isVoiceRecording() + onContentModelChanged: if(contentModel){ + tempFile.createFileFromContent(contentModel, false); + } + + TemporaryFile { + id: tempFile + } + sourceComponent: Item{ id: loadedItem property bool isPlaying : vocalPlayer.item && vocalPlayer.item.playbackState === SoundPlayer.PlayingState @@ -59,7 +69,7 @@ Loader{ } } sourceComponent: SoundPlayer { - source: mainItem.contentModel && mainItem.contentModel.filePath + source: mainItem.contentModel && mainItem.filePath onStopped:{ mediaProgressBar.value = 101 } diff --git a/linphone-app/ui/modules/Linphone/Chat/ChatFileMessage.qml b/linphone-app/ui/modules/Linphone/Chat/ChatFileMessage.qml index a70225922..cca019aae 100644 --- a/linphone-app/ui/modules/Linphone/Chat/ChatFileMessage.qml +++ b/linphone-app/ui/modules/Linphone/Chat/ChatFileMessage.qml @@ -280,14 +280,21 @@ Row { onClicked: { if(rectangle.isTransferring) mainRow.contentModel.cancelDownloadFile() - else if (Utils.pointIsInItem(this, thumbnailProvider, mouse)) { - mainRow.contentModel.openFile() - } else if (mainRow.contentModel && mainRow.contentModel.wasDownloaded) { - mainRow.contentModel.openFile(true)// Show directory + else if( !mainRow.contentModel.wasDownloaded) { thumbnailProvider.state = '' - } else { mainRow.contentModel.downloadFile() + }else if (Utils.pointIsInItem(this, thumbnailProvider, mouse)) { + window.attachVirtualWindow(Utils.buildCommonDialogUri('FileViewDialog'), { + contentModel: mainRow.contentModel, + }, function (status) { + }) + } else if (mainRow.contentModel ) { thumbnailProvider.state = '' + mainRow.contentModel.openFile(true)// Show directory + } else { + thumbnailProvider.state = '' + mainRow.contentModel.downloadFile() + } } onExited: thumbnailProvider.state = '' diff --git a/linphone-app/ui/modules/Linphone/Styles/Chat/ChatAudioMessageStyle.qml b/linphone-app/ui/modules/Linphone/Styles/Chat/ChatAudioMessageStyle.qml index 2aba28306..aaccca315 100644 --- a/linphone-app/ui/modules/Linphone/Styles/Chat/ChatAudioMessageStyle.qml +++ b/linphone-app/ui/modules/Linphone/Styles/Chat/ChatAudioMessageStyle.qml @@ -12,7 +12,7 @@ QtObject { property int emptySpace: 10 property color color: ColorsList.add(sectionName, 'q').color - property color backgroundColor: ColorsList.add(sectionName+'_bg', 'a').color + property color backgroundColor: ColorsList.add(sectionName+'_bg', 'e').color property QtObject pauseAction: QtObject { property int iconSize: 25 diff --git a/linphone-app/ui/views/App/Calls/IncallFullscreen.qml b/linphone-app/ui/views/App/Calls/IncallFullscreen.qml index 27d63c4ce..b7dffe107 100644 --- a/linphone-app/ui/views/App/Calls/IncallFullscreen.qml +++ b/linphone-app/ui/views/App/Calls/IncallFullscreen.qml @@ -591,41 +591,9 @@ Window { visible: SettingsModel.showTelKeypadAutomatically y: 50 } - MouseArea{ - Timer { - id: hideButtonsTimer - property bool realRunning : false - property bool firstUse: true - - interval: firstUse ? 500 : 4000 - running: false - triggeredOnStart: !firstUse - onTriggered: {if(!firstUse && realRunning != running) realRunning = running - firstUse = false} - function startTimer(){ - if(!firstUse || !running) - restart(); - } - function stopTimer(){ - stop() - realRunning = false - hideButtonsTimer.firstUse = false - } - } - + + HoveringMouseArea{ + id: hideButtonsTimer anchors.fill: parent - acceptedButtons: Qt.NoButton - propagateComposedEvents: true - cursorShape: undefined - //cursorShape: Qt.ArrowCursor - onEntered: hideButtonsTimer.startTimer() - onExited: { - var cursorPosition = UtilsCpp.getCursorPosition() - mapToItem(window.contentItem, cursorPosition.x, cursorPosition.y) - if (cursorPosition.x <= 0 || cursorPosition.y <= 0 - || cursorPosition.x >= width || cursorPosition.y >= height) - hideButtonsTimer.stopTimer() - } - onPositionChanged: hideButtonsTimer.startTimer() } } diff --git a/linphone-app/ui/views/App/Settings/SettingsAdvanced.qml b/linphone-app/ui/views/App/Settings/SettingsAdvanced.qml index 3892883f5..faeae5e41 100644 --- a/linphone-app/ui/views/App/Settings/SettingsAdvanced.qml +++ b/linphone-app/ui/views/App/Settings/SettingsAdvanced.qml @@ -4,6 +4,7 @@ import QtQuick.Controls 2.5 import Common 1.0 import Linphone 1.0 +import Utils 1.0 import App.Styles 1.0 import Linphone.Styles 1.0 @@ -327,6 +328,56 @@ TabContainer { } } + // ------------------------------------------------------------------------- + // VFS + // ------------------------------------------------------------------------- + + Form { + //: 'VFS' + title: qsTr('vfsTitle') + width: parent.width + + FormLine { + FormGroup { + //: 'Encrypt all the application' : Label to encrypt application + label: qsTr('vfsEncryption') + + Switch { + checked: SettingsModel.isVfsEncrypted + + onClicked: { + window.attachVirtualWindow(Utils.buildCommonDialogUri('ConfirmDialog'), { + descriptionText: (checked + //: 'Are you sure to deactivate the encryption? The application will exit and all your data will be lost. You must delete them before using the application.' : Explanation to deactivate the VFS encryption. + ? qsTr('vfsDeactivation') + //: 'Are you sure to activate the encryption? You cannot revert without deleting ALL your data' : Explanation to activate the VFS encryption. + : qsTr('vfsActivation')) + , buttonTexts : (checked + ?[qsTr('cancel'), + //: 'Delete data' : Action to delete all data. + qsTr('deleteData')] + : [qsTr('cancel'), qsTr('confirm')]) + , height:320 + }, function (status) { + if(status > 0){ + if (status == 1 && checked){// Test on 1 in case if we want more options (aka more buttons) + window.attachVirtualWindow(Utils.buildCommonDialogUri('ConfirmDialog'), { + //: 'The application will delete your application data files. Do you confirm ?' + descriptionText: qsTr('vfsDeletion') + , height: 320 + }, function (deleteStatus) { + if( deleteStatus) + SettingsModel.setVfsEncrypted(!checked, true) + }) + }else + SettingsModel.setVfsEncrypted(!checked, false) + } + }) + } + } + } + } + } // ------------------------------------------------------------------------- // Developer settings. // -------------------------------------------------------------------------