diff --git a/Frontend/DashboardsViewer/content/CMakeLists.txt b/Frontend/DashboardsViewer/content/CMakeLists.txt index 257d6f9..5a2aeb4 100644 --- a/Frontend/DashboardsViewer/content/CMakeLists.txt +++ b/Frontend/DashboardsViewer/content/CMakeLists.txt @@ -10,6 +10,7 @@ qt6_add_qml_module(content # Screens screens/Dashboard.qml screens/DashboardSelector.qml + screens/LoadingScreen.qml screens/Login.qml # Uis diff --git a/Frontend/DashboardsViewer/content/dataSources/FileDownloadDataSource.qml b/Frontend/DashboardsViewer/content/dataSources/FileDownloadDataSource.qml index 86fac16..43c4b64 100644 --- a/Frontend/DashboardsViewer/content/dataSources/FileDownloadDataSource.qml +++ b/Frontend/DashboardsViewer/content/dataSources/FileDownloadDataSource.qml @@ -1,6 +1,8 @@ import QtQuick 2.15 import OpenTeraLibs.UserClient 1.0 +import DashboardsViewer + Item { id: fileDownloadDataSource property string url: "" // Empty URL @@ -9,13 +11,13 @@ Item { property string filename: "" property string archiveUuid: "" property bool downloading: false + property bool compressing: false signal downloadProgress(var bytesReceived, var bytesTotal); signal downloadStarted(); signal downloadFinished(); signal downloadFailed(); - function downloadFile() { if (downloading){ @@ -30,7 +32,7 @@ Item { var fileDownloader = UserClient.downloadFile(filename, url, params); fileDownloader.finished.connect(function() { - console.log("Finished"); + //console.log("Finished"); downloadFinished(); downloading = false; }); @@ -42,7 +44,7 @@ Item { } else { downloadFailed(); - downloading = false; + downloading = false; } } @@ -55,12 +57,42 @@ Item { params = {"id_participant": id_participant} var reply = UserClient.get("/api/user/assets/archive", params) + compressing = true; + reply.requestSucceeded.connect(function(response, statusCode) { - console.log(response, statusCode); + //console.log(response, statusCode); }); } } + function downloadSessionArchive(id_session) { + + if (id_session) + { + // Step #1, Call the Archive API + params = {"id_session": id_session} + var reply = UserClient.get("/api/user/assets/archive", params) + + compressing = true; + + reply.requestSucceeded.connect(function(response, statusCode) { + //console.log(response, statusCode); + }); + } + } + + function downloadSpecificAsset(asset_uuid){ + params = {"asset_uuid": asset_uuid, "with_urls": true} + var reply = UserClient.get("/api/user/assets", params) + reply.requestSucceeded.connect(function(response, statusCode) { + // Download file + params = {"asset_uuid": asset_uuid, "access_token": response[0].access_token}; + url = response[0].asset_url.replace(UserClient.url, "") + downloadFile(); + }); + + } + Connections { target: UserClient onArchiveEvent: function(event) { @@ -71,6 +103,7 @@ Item { url = url_parts[0]; params = {"archive_uuid": event.archiveUuid}; downloadFile(); + compressing = false; } } } diff --git a/Frontend/DashboardsViewer/content/delegates/ParticipantDelegate.qml b/Frontend/DashboardsViewer/content/delegates/ParticipantDelegate.qml index 206ff11..07e942c 100644 --- a/Frontend/DashboardsViewer/content/delegates/ParticipantDelegate.qml +++ b/Frontend/DashboardsViewer/content/delegates/ParticipantDelegate.qml @@ -170,6 +170,25 @@ BaseDelegate { FileDownloadDataSource{ id: fileDownloader + onCompressingChanged:{ + if (screenLoading !== undefined){ + screenLoading.text = qsTr("Compressing data..."); + screenLoading.visible = compressing; + screenLoading.progressValue = -1; + } + } + onDownloadingChanged: { + if (screenLoading !== undefined){ + screenLoading.text = qsTr("Downloading..."); + screenLoading.visible = downloading; + screenLoading.progressValue = 0; + } + } + onDownloadProgress: function(bytesReceived, bytesTotal){ + if (screenLoading !== undefined){ + screenLoading.progressValue = (bytesReceived / bytesTotal) * 100 + } + } } FileDialog { @@ -179,7 +198,7 @@ BaseDelegate { fileMode: FileDialog.SaveFile //URL currentFolder: StandardPaths.writableLocation(StandardPaths.DownloadLocation) - selectedFile: currentFolder + "/participant.zip" //model[model.dataSource.fieldDisplayName] + ".zip" + selectedFile: currentFolder + "/" + model[model.dataSource.fieldDisplayName] + ".zip" //"participant.zip" //model[model.dataSource.fieldDisplayName] + ".zip" onAccepted: function() { fileDownloader.filename = saveFileDialog.currentFile; fileDownloader.downloadParticipantArchive(model[model.dataSource.fieldIdName]) diff --git a/Frontend/DashboardsViewer/content/delegates/SessionDelegate.qml b/Frontend/DashboardsViewer/content/delegates/SessionDelegate.qml index afcbe04..0344943 100644 --- a/Frontend/DashboardsViewer/content/delegates/SessionDelegate.qml +++ b/Frontend/DashboardsViewer/content/delegates/SessionDelegate.qml @@ -1,9 +1,13 @@ import QtQuick 2.15 import QtQuick.Controls 2.15 import QtQuick.Layouts 2.15 +import QtQuick.Dialogs +import QtCore import DashboardsViewer import "../ui" +import "../widgets" +import "../dataSources" BaseDelegate { id: myDelegate @@ -13,6 +17,8 @@ BaseDelegate { property int daysWarningThreshold: 7 property int daysErrorThreshold: 14 + property bool showDownloadAssets: true + property bool isCurrentItem: ListView ? ListView.isCurrentItem : false states: [ @@ -113,6 +119,31 @@ BaseDelegate { border.color: isCurrentItem ? "lightgrey" : "black" border.width: isCurrentItem ? 5 : 1 radius: 5 + MouseArea { + id: mouseArea + anchors.fill: parent + onDoubleClicked: { + //console.log("SessionDelegate clicked"); + if (stackView) { + stackView.push("../widgets/SessionViewerWidget.qml", {"session": model}) + } + } + onPressAndHold: { + //console.log("SessionDelegate long pressed"); + + if (stackView) { + stackView.push("../widgets/SessionViewerWidget.qml", {"session": model}) + } + + } + onClicked: { + onClicked: { + if (myDelegate.ListView) + myDelegate.ListView.view.currentIndex = index; + model.dataSource.itemSelected(model[model.dataSource.fieldIdName]) + } + } + } } RowLayout { @@ -190,17 +221,16 @@ BaseDelegate { Item{ Layout.fillWidth: true } + } - Text{ - id: txtName - Layout.fillWidth: true - text: model.session_name - font.pixelSize: Constants.baseFontSize - wrapMode: Text.WordWrap - style: Text.Outline - color: Constants.textColor - } - + Text{ + id: txtName + Layout.fillWidth: true + text: model.session_name + font.pixelSize: Constants.baseFontSize + wrapMode: Text.WordWrap + style: Text.Outline + color: Constants.textColor } Text{ @@ -218,31 +248,59 @@ BaseDelegate { } } - } + ImageButtonWidget{ + id: btnDownload + visible: model.session_assets_count > 0 && showDownloadAssets + imgPath: "../images/icons/data.png" + onClicked: { + if (dashboardViewerApp.isWebAssembly()) { + //This will use the browser download function. Download UI is provided by browser. + fileDownloader.filename = model[model.dataSource.fieldName] + + //DownloadFile returnes a null object in WebASM + fileDownloader.downloadParticipantArchive(model[model.dataSource.fieldIdName]) + } else { + //console.log('WebAssembly is not supported'); + saveFileDialog.open(); + } - MouseArea { - id: mouseArea - anchors.fill: parent - onDoubleClicked: { - console.log("SessionDelegate clicked"); - if (stackView) { - stackView.push("../widgets/SessionViewerWidget.qml", {"session": model}) } } - onPressAndHold: { - console.log("SessionDelegate long pressed"); + } - if (stackView) { - stackView.push("../widgets/SessionViewerWidget.qml", {"session": model}) + FileDownloadDataSource{ + id: fileDownloader + onCompressingChanged:{ + if (screenLoading !== undefined){ + screenLoading.text = qsTr("Compressing data..."); + screenLoading.visible = compressing; + screenLoading.progressValue = -1; } - } - onClicked: { - onClicked: { - if (myDelegate.ListView) - myDelegate.ListView.view.currentIndex = index; - model.dataSource.itemSelected(model[model.dataSource.fieldIdName]) + onDownloadingChanged: { + if (screenLoading !== undefined){ + screenLoading.text = qsTr("Downloading..."); + screenLoading.visible = downloading; + screenLoading.progressValue = 0; + } + } + onDownloadProgress: function(bytesReceived, bytesTotal){ + if (screenLoading !== undefined){ + screenLoading.progressValue = (bytesReceived / bytesTotal) * 100 } } } + FileDialog { + id: saveFileDialog + nameFilters: ["Zip files (*.zip)"] + defaultSuffix: ".zip" + fileMode: FileDialog.SaveFile + //URL + currentFolder: StandardPaths.writableLocation(StandardPaths.DownloadLocation) + selectedFile: currentFolder + "/" + model[model.dataSource.fieldDisplayName] + ".zip" + onAccepted: function() { + fileDownloader.filename = saveFileDialog.currentFile; + fileDownloader.downloadSessionArchive(model[model.dataSource.fieldIdName]) + } + } } // Item diff --git a/Frontend/DashboardsViewer/content/screens/Dashboard.qml b/Frontend/DashboardsViewer/content/screens/Dashboard.qml index 81818d5..bb5e866 100644 --- a/Frontend/DashboardsViewer/content/screens/Dashboard.qml +++ b/Frontend/DashboardsViewer/content/screens/Dashboard.qml @@ -53,34 +53,14 @@ Item { } } - /*Text { - id: dashboardText - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: parent.top - text: qsTr("DASHBOARD") - font.pixelSize: 60 - height: 60 - horizontalAlignment: Text.AlignHCenter + LoadingScreen{ + id: screenLoading + visible: false + z: 3 } - Button { - id: closeButton - anchors.left: parent.left - anchors.top: parent.top - width: 150 - height: 60 - text: qsTr("Close") - onClicked: function () { - stackview.pop() - } - }*/ - StackView { id: dashboardStackView anchors.fill: parent - /*anchors.top: dashboardText.bottom - anchors.bottom: parent.bottom - anchors.left: parent.left - anchors.right: parent.right*/ } } diff --git a/Frontend/DashboardsViewer/content/screens/LoadingScreen.qml b/Frontend/DashboardsViewer/content/screens/LoadingScreen.qml new file mode 100644 index 0000000..319dec9 --- /dev/null +++ b/Frontend/DashboardsViewer/content/screens/LoadingScreen.qml @@ -0,0 +1,36 @@ +import QtQuick +import QtQuick.Controls + +import DashboardsViewer + +Item { + anchors.fill: parent + + property alias text: txtInfos.text + property int progressValue: -1 + + Rectangle{ + id: recFiller + anchors.fill: parent + color: "#aa000000" + Column{ + anchors.centerIn: parent + spacing: 10 + Text{ + id: txtInfos + font.pixelSize: Constants.largeFontSize + color: "white" + text: qsTr("Loading...") + } + ProgressBar{ + indeterminate: progressValue < 0 + to: 100 + value: progressValue >= 0 ? progressValue : 0 + width: parent.width + } + } + MouseArea{ + anchors.fill: parent + } + } +} diff --git a/Frontend/DashboardsViewer/content/widgets/ImageButtonWidget.qml b/Frontend/DashboardsViewer/content/widgets/ImageButtonWidget.qml index ab8dcbf..b1b1c58 100644 --- a/Frontend/DashboardsViewer/content/widgets/ImageButtonWidget.qml +++ b/Frontend/DashboardsViewer/content/widgets/ImageButtonWidget.qml @@ -9,6 +9,7 @@ BaseWidget { property alias text: control.text required property string imgPath + property alias textControl: textItem implicitHeight: control.implicitHeight implicitWidth: control.implicitWidth + 10 diff --git a/Frontend/DashboardsViewer/content/widgets/SessionViewerWidget.qml b/Frontend/DashboardsViewer/content/widgets/SessionViewerWidget.qml index 37d9751..9bbe3cf 100644 --- a/Frontend/DashboardsViewer/content/widgets/SessionViewerWidget.qml +++ b/Frontend/DashboardsViewer/content/widgets/SessionViewerWidget.qml @@ -130,13 +130,14 @@ Item { Rectangle { id: sessionComments Layout.fillWidth: true - implicitHeight: layoutComments.implicitHeight + implicitHeight: layoutComments.implicitHeight + layoutComments.anchors.margins * 2 color: Constants.highlightColor radius: 5 visible: session.session_comments ColumnLayout{ id: layoutComments anchors.fill: parent + anchors.margins: 10 Text { id: sessionCommentsText text: session.session_comments @@ -213,7 +214,9 @@ Item { clip: true visible: count > 0 - interactive: contentHeight < height + interactive: contentHeight > height + ScrollBar.vertical: FlickableScrollBar {} + spacing: 2 delegate: Item { @@ -225,40 +228,29 @@ Item { return model } - BasicButton { + ImageButtonWidget{ id: singleAssetDownloadButton - anchors.fill: parent - text: delegateModel().asset_name + " [" + delegateModel().asset_uuid + "]" + text: delegateModel().asset_name + imgPath: "../images/icons/data.png" + textControl.color: "black" + textControl.style: Text.Normal onClicked: { - //console.log("Download button clicked for asset: " + delegateModel().asset_name + " [" + delegateModel().asset_uuid + "]"); - if (dashboardViewerApp.isWebAssembly()) { - //console.log("WebAssembly is supported...") //This will use the browser download function. Download UI is provided by browser. fileDownloadDataSource.filename = delegateModel().asset_name //DownloadFile returnes a null object in WebASM - fileDownloadDataSource.downloadFile(); + fileDownloadDataSource.downloadSpecificAsset(delegateModel().asset_uuid) } else { - //console.log('WebAssembly is not supported'); saveFileDialog.open(); } } } - Text { - id: singleAssetInfoText - anchors.right: singleAssetDownloadButton.right - anchors.top: singleAssetDownloadButton.top - anchors.bottom: singleAssetDownloadButton.bottom - //text: "Hello World!" - } FileDownloadDataSource { id: fileDownloadDataSource - url: "/file/api/assets" filename: delegateModel().asset_name - params: {"asset_uuid": delegateModel().asset_uuid, "access_token": delegateModel().access_token} } BaseDataSource { @@ -297,17 +289,18 @@ Item { { target: fileDownloadDataSource onDownloadProgress: function(bytesReceived, bytesTotal){ - console.log("DownloadProgressDialog progress: ", bytesReceived, bytesTotal); + //console.log("DownloadProgressDialog progress: ", bytesReceived, bytesTotal); progressBar.value = bytesReceived / bytesTotal * 100; } onDownloadFinished: function() { - console.log("DownloadProgressDialog finished"); + //console.log("DownloadProgressDialog finished"); downloadProgressDialog.enabled = true; + downloadProgressDialog.close(); } } onAccepted: { - console.log("DownloadProgressDialog accepted"); + //console.log("DownloadProgressDialog accepted"); saveFileDialog.open(); } } @@ -320,10 +313,10 @@ Item { currentFolder: StandardPaths.writableLocation(StandardPaths.DownloadLocation) currentFile: delegateModel().asset_name onAccepted: function() { - console.log("SaveFileDialog accepted"); + //console.log("SaveFileDialog accepted"); fileDownloadDataSource.filename = saveFileDialog.currentFile; downloadProgressDialog.open(); - fileDownloadDataSource.downloadFile(); + fileDownloadDataSource.downloadSpecificAsset(delegateModel().asset_uuid) } } } // Item (delegate) @@ -340,10 +333,8 @@ Item { } } - - // Download Assets button - BasicButton { + /* BasicButton { id: downloadAssetsButton Layout.fillWidth: false Layout.fillHeight: false @@ -355,7 +346,7 @@ Item { console.log("Download Assets button clicked") } - } + }*/ } } diff --git a/Frontend/DashboardsViewer/resources/json/TestDashboardv2.json b/Frontend/DashboardsViewer/resources/json/TestDashboardv2.json index feedb2e..3801a83 100644 --- a/Frontend/DashboardsViewer/resources/json/TestDashboardv2.json +++ b/Frontend/DashboardsViewer/resources/json/TestDashboardv2.json @@ -64,14 +64,6 @@ "Layout.fillWidth": {"type": "bool", "value": "true"}, "Layout.fillHeight": {"type": "bool", "value": "true"} } - }, - { - "type": "ButtonWidget", - "id": "btnDownloadAssets", - "properties": { - "text": {"type": "string", "value": "Download assets"}, - "visible": {"type": "raw", "value": "participantSessionList.dataSource.model.count"} - } } ], "properties":{ diff --git a/Frontend/DashboardsViewer/translations/DashboardsViewerApp_en.ts b/Frontend/DashboardsViewer/translations/DashboardsViewerApp_en.ts index 7b8a234..46d9c97 100644 --- a/Frontend/DashboardsViewer/translations/DashboardsViewerApp_en.ts +++ b/Frontend/DashboardsViewer/translations/DashboardsViewerApp_en.ts @@ -96,6 +96,15 @@ + + LoadingScreen + + + + Loading... + + + Login @@ -138,44 +147,68 @@ ParticipantDelegate - - + + Last session + + + + Compressing data... + + + + + + Downloading... + + SessionDelegate - - + + Completed - - + + Cancelled - - + + Terminated - - + + In progress - - + + Planned + + + + Compressing data... + + + + + + Downloading... + + SessionEventDelegate @@ -305,14 +338,14 @@ - - + + Assets - - + + No assets @@ -362,7 +395,7 @@ UserComManager - + Invalid username or password. diff --git a/Frontend/DashboardsViewer/translations/DashboardsViewerApp_fr.ts b/Frontend/DashboardsViewer/translations/DashboardsViewerApp_fr.ts index b74973b..a382c3e 100644 --- a/Frontend/DashboardsViewer/translations/DashboardsViewerApp_fr.ts +++ b/Frontend/DashboardsViewer/translations/DashboardsViewerApp_fr.ts @@ -112,6 +112,15 @@ Titre + + LoadingScreen + + + + Loading... + Chargement en cours... + + Login @@ -154,44 +163,68 @@ ParticipantDelegate - - + + Last session Dernière séance + + + + Compressing data... + Compression des données... + + + + + Downloading... + Téléchargement... + SessionDelegate - - + + Completed Complétée - - + + Cancelled Annulée - - + + Terminated Terminée - - + + In progress En cours - - + + Planned Planifiée + + + + Compressing data... + Compression des données... + + + + + Downloading... + Téléchargement... + SessionEventDelegate @@ -321,14 +354,14 @@ Planifiée - - + + Assets Données - - + + No assets Aucune donnée @@ -382,7 +415,7 @@ UserComManager - + Invalid username or password. Utilisateur ou mot de passe invalide.