diff --git a/resources/icons/check_circle_24dp.svg b/resources/icons/check_circle_24dp.svg new file mode 100644 index 000000000..0928fee00 --- /dev/null +++ b/resources/icons/check_circle_24dp.svg @@ -0,0 +1,3 @@ + + + diff --git a/resources/icons/fiber_manual_record_24dp.svg b/resources/icons/fiber_manual_record_24dp.svg deleted file mode 100644 index 7ba3488ba..000000000 --- a/resources/icons/fiber_manual_record_24dp.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/resources/icons/re_record_24dp.svg b/resources/icons/re_record_24dp.svg deleted file mode 100644 index 09b45837a..000000000 --- a/resources/icons/re_record_24dp.svg +++ /dev/null @@ -1,11 +0,0 @@ - - - - - diff --git a/resources/icons/record_round_black_24dp.svg b/resources/icons/record_round_black_24dp.svg new file mode 100644 index 000000000..bef06bb0d --- /dev/null +++ b/resources/icons/record_round_black_24dp.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/resources/icons/restart_black_24dp.svg b/resources/icons/restart_black_24dp.svg new file mode 100644 index 000000000..d44467185 --- /dev/null +++ b/resources/icons/restart_black_24dp.svg @@ -0,0 +1,3 @@ + + + diff --git a/resources/icons/stop_24dp_red.svg b/resources/icons/stop_24dp_red.svg deleted file mode 100644 index 1ec9ca998..000000000 --- a/resources/icons/stop_24dp_red.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/resources/icons/stop_rectangle_24dp.svg b/resources/icons/stop_rectangle_24dp.svg new file mode 100644 index 000000000..61058c3ba --- /dev/null +++ b/resources/icons/stop_rectangle_24dp.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/app/commoncomponents/PhotoboothPopup.qml b/src/app/commoncomponents/PhotoboothPopup.qml index 092e2f7fd..eb66fe3ca 100644 --- a/src/app/commoncomponents/PhotoboothPopup.qml +++ b/src/app/commoncomponents/PhotoboothPopup.qml @@ -64,7 +64,8 @@ BaseModalDialog { RecordBox { id: recordBox - anchors.centerIn: parent + x: 100 + y: 100 isPhoto: true visible: false @@ -120,14 +121,6 @@ BaseModalDialog { onClicked: { recordBox.parent = buttonsRowLayout - - recordBox.x = Qt.binding(function() { - var buttonCenterX = buttonsRowLayout.width / 2 - return buttonCenterX - recordBox.width / 2 - }) - recordBox.y = Qt.binding(function() { - return - recordBox.height / 2 - }) startBooth() } } diff --git a/src/app/constant/JamiTheme.qml b/src/app/constant/JamiTheme.qml index afe5dc029..938f98095 100644 --- a/src/app/constant/JamiTheme.qml +++ b/src/app/constant/JamiTheme.qml @@ -169,6 +169,12 @@ Item { property color spinboxBackgroundColor: darkTheme ? editBackgroundColor : selectedColor property color spinboxBorderColor: darkTheme ? "#1D5F70" : "#A3C2DA" + //RecordBox + property color screenshotButtonColor: "#CC0022" + property color recordBoxcloseButtonColor: "#8d8a87" + property color recordBoxHoverColor: "#4D4D4D" + property color recordBoxButtonColor: "#272727" + // Toast property color toastColor: darkTheme ? "#f0f0f0" : "#000000" property color toastRectColor: !darkTheme ? "#f0f0f0" : "#000000" diff --git a/src/app/mainview/components/ChatViewFooter.qml b/src/app/mainview/components/ChatViewFooter.qml index 4523d273b..e47a404cf 100644 --- a/src/app/mainview/components/ChatViewFooter.qml +++ b/src/app/mainview/components/ChatViewFooter.qml @@ -193,12 +193,14 @@ Rectangle { } onVideoRecordMessageButtonClicked: { - recordBox.y = -recordBox.height; + recordBox.y = -recordBox.height - 200; + recordBox.x = recordBox.width + 200 recordBox.openRecorder(true); } onAudioRecordMessageButtonClicked: { - recordBox.y = -recordBox.height; + recordBox.y = -recordBox.height - 150; + recordBox.x = recordBox.width + 200; recordBox.openRecorder(false); } diff --git a/src/app/mainview/components/RecordBox.qml b/src/app/mainview/components/RecordBox.qml index c7cb03600..c3895a138 100644 --- a/src/app/mainview/components/RecordBox.qml +++ b/src/app/mainview/components/RecordBox.qml @@ -38,9 +38,10 @@ Popup { property int state: RecordBox.States.INIT property bool isVideo: false property bool isPhoto: false + property bool isAudio: false property bool showVideo: (root.isVideo && VideoDevices.listSize !== 0) property int preferredWidth: 320 - property int preferredHeight: 240 + property int preferredHeight: 500 property int btnSize: 40 property int offset: 3 @@ -56,6 +57,7 @@ Popup { function openRecorder(vid) { isVideo = vid; + isAudio = !vid && !isPhoto; updateState(RecordBox.States.INIT); if (isVideo) { localVideo.startWithId(VideoDevices.getDefaultDevice()); @@ -136,260 +138,315 @@ Popup { } } - background: Item { - } // Computed by id: box, to do the layer on LocalVideo - - width: preferredWidth - height: isVideo ? previewWidget.height + 80 : preferredHeight Rectangle { - id: box + id: boxBackground radius: 5 anchors.fill: parent - color: JamiTheme.backgroundColor - - PushButton { - id: cancelBtn - objectName: "cancelBtn" - z: 1 - - normalColor: "transparent" - hoveredColor: Qt.rgba(255, 255, 255, 0.2) - imageColor: isVideo ? JamiTheme.whiteColor : JamiTheme.textColor - - preferredSize: 12 - - source: JamiResources.round_close_24dp_svg - toolTipText: JamiStrings.back - - anchors.right: box.right - anchors.top: box.top - anchors.margins: 8 - - focusPolicy: Qt.TabFocus - onClicked: { - closeRecorder(); - updateState(RecordBox.States.INIT); - } - } - - Item { - // Else it will be resized by the layer effect - id: photoMask - visible: false - anchors.fill: parent - Rectangle { - anchors.centerIn: parent - height: parent.height - width: parent.height - radius: height / 2 - } - } + width: 300 + height: 300 Rectangle { - id: rectBox - visible: false - anchors.fill: parent + radius: 5 - } + id: previewWidget + anchors.centerIn: parent + height: root.isAudio ? 100 : 300 + width: 300 + color: root.isAudio ? JamiTheme.secondaryBackgroundColor : "transparent" - ColumnLayout { - id: recordItem - anchors.fill: parent - spacing: 0 - Layout.alignment: Qt.AlignTop - - // Video Image { id: screenshotImg visible: root.showVideo && root.isPhoto && btnSend.visible - Layout.alignment: Qt.AlignHCenter | Qt.AlignTop - - sourceSize.width: parent.width - sourceSize.height: width * localVideo.invAspectRatio + anchors.fill: parent + fillMode: Image.PreserveAspectCrop // Ajuste l'image tout en préservant l'aspect source: root.photo === "" ? "" : "data:image/png;base64," + root.photo } - // video Preview - Rectangle { - id: previewWidget + LocalVideo { + id: localVideo + anchors.fill: parent visible: root.showVideo && !screenshotImg.visible - Layout.alignment: Qt.AlignHCenter | Qt.AlignTop - height: localVideo.width * localVideo.invAspectRatio - width: parent.width + layer.enabled: true + layer.effect: OpacityMask { + maskSource: rectBox + } - color: JamiTheme.primaryForegroundColor - - LocalVideo { - id: localVideo + Rectangle { + id: rectBox + visible: false anchors.fill: parent + radius: 5 + } + } - layer.enabled: true - layer.effect: OpacityMask { - maskSource: rectBox - } + Rectangle { + anchors.fill: parent + color: "black" + opacity: 0.6 + visible: root.isPhoto + radius: 5 + layer.enabled: true + layer.effect: OpacityMask { + anchors.centerIn: parent + maskSource: photoMask + invert: true + } + + Item { + // Else it will be resized by the layer effect + id: photoMask + visible: false + anchors.fill: parent Rectangle { - anchors.fill: parent - color: "black" - opacity: 0.6 - visible: root.isPhoto - - layer.enabled: true - layer.effect: OpacityMask { - anchors.centerIn: parent - maskSource: photoMask - invert: true - } + anchors.horizontalCenter: parent.horizontalCenter + anchors.top: parent.top + anchors.topMargin: 20 + height: 200 + width: 200 + radius: height / 2 } } } - RowLayout { - id: controls - Layout.alignment: Qt.AlignCenter - Layout.fillWidth: true - spacing: 24 - Layout.bottomMargin: isVideo ? 8 : 0 + ColumnLayout{ + id: mainLayout - PushButton { - id: recordButton - objectName: "recordButton" - Layout.alignment: Qt.AlignCenter + anchors.fill: parent + Component.onCompleted: print("mainLayout width: " + width + " height: " + height) - preferredSize: btnSize + JamiPushButton { + id: cancelBtn + objectName: "cancelBtn" + z: 1 - normalColor: isVideo ? "transparent" : JamiTheme.backgroundColor - hoveredColor: Qt.rgba(255, 255, 255, 0.2) + Layout.alignment: Qt.AlignRight | Qt.AlignTop + Layout.preferredHeight: 20 + Layout.preferredWidth: 20 + Layout.topMargin: 5 + Layout.rightMargin: 5 - source: JamiResources.fiber_manual_record_24dp_svg - imageColor: JamiTheme.recordIconColor + imageColor: hovered ? JamiTheme.whiteColor : JamiTheme.recordBoxcloseButtonColor + normalColor: "transparent" + hoveredColor: JamiTheme.recordBoxHoverColor + source: JamiResources.round_close_24dp_svg + toolTipText: JamiStrings.back focusPolicy: Qt.TabFocus + onClicked: { - updateState(RecordBox.States.RECORDING); - if (!root.isPhoto) - startRecording(); - } - } - - PushButton { - id: screenshotBtn - objectName: "screenshotBtn" - Layout.alignment: Qt.AlignCenter - - preferredSize: btnSize - - normalColor: isVideo ? "transparent" : JamiTheme.backgroundColor - hoveredColor: Qt.rgba(255, 255, 255, 0.2) - border.width: 1 - border.color: imageColor - - source: JamiResources.fiber_manual_record_24dp_svg - imageColor: UtilsAdapter.luma(JamiTheme.backgroundColor) ? "white" : JamiTheme.redColor - - focusPolicy: Qt.TabFocus - onClicked: { - root.photo = videoProvider.captureVideoFrame(VideoDevices.getDefaultDevice()); - updateState(RecordBox.States.REC_SUCCESS); - } - } - - PushButton { - id: btnStop - objectName: "btnStop" - Layout.alignment: Qt.AlignCenter - - preferredSize: btnSize - - normalColor: isVideo ? "transparent" : JamiTheme.backgroundColor - hoveredColor: Qt.rgba(255, 255, 255, 0.2) - - source: JamiResources.stop_24dp_red_svg - imageColor: UtilsAdapter.luma(JamiTheme.backgroundColor) ? "white" : JamiTheme.buttonTintedBlue - border.width: 1 - border.color: imageColor - - focusPolicy: Qt.TabFocus - onClicked: { - if (!root.isPhoto) - stopRecording(); - updateState(RecordBox.States.REC_SUCCESS); - } - } - - PushButton { - id: btnRestart - objectName: "btnRestart" - Layout.alignment: Qt.AlignCenter - - preferredSize: btnSize - - normalColor: isVideo ? "transparent" : JamiTheme.backgroundColor - - source: JamiResources.re_record_24dp_svg - hoveredColor: Qt.rgba(255, 255, 255, 0.2) - imageColor: UtilsAdapter.luma(JamiTheme.backgroundColor) ? "white" : JamiTheme.buttonTintedBlue - border.width: 1 - border.color: imageColor - - focusPolicy: Qt.TabFocus - onClicked: { - if (!root.isPhoto) - stopRecording(); - updateState(RecordBox.States.INIT); - } - } - - PushButton { - id: btnSend - objectName: "btnSend" - Layout.alignment: Qt.AlignCenter - - preferredSize: btnSize - - normalColor: isVideo ? "transparent" : JamiTheme.backgroundColor - - source: JamiResources.check_black_24dp_svg - imageColor: UtilsAdapter.luma(JamiTheme.backgroundColor) ? "white" : JamiTheme.buttonTintedBlue - border.width: 1 - border.color: imageColor - - focusPolicy: Qt.TabFocus - onClicked: { - if (!root.isPhoto) { - stopRecording(); - sendRecord(); - } else if (root.photo !== "") { - root.validatePhoto(root.photo); - } closeRecorder(); updateState(RecordBox.States.INIT); } } - Timer { - id: timer + RowLayout { + id: controls - interval: 1000 - running: false - repeat: true + Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom + Layout.fillWidth: true - onTriggered: updateTimer() + spacing: 2 + Layout.bottomMargin: 20//isVideo ? 8 : 0 + Component.onCompleted: print("controls width: " + width + " height: " + height) + + JamiPushButton { + id: recordButton + + objectName: "recordButton" + Layout.alignment: Qt.AlignCenter + preferredSize: btnSize + + source: JamiResources.record_black_24dp_svg + imageColor: JamiTheme.whiteColor + imageContainerHeight: 20 + imageContainerWidth: 20 + + focusPolicy: Qt.TabFocus + + background: RoundedBorderRectangle { + opacity: recordButton.hovered ? 1 : 0.7 + fillColor: recordButton.hovered ? JamiTheme.recordBoxHoverColor : JamiTheme.recordBoxButtonColor + radius: { + "tl": 5, + "tr": root.isAudio ? 0 : 5, + "br": root.isAudio ? 0 : 5, + "bl": 5 + } + } + + onClicked: { + updateState(RecordBox.States.RECORDING); + if (!root.isPhoto) + startRecording(); + } + } + JamiPushButton { + id: screenshotBtn + objectName: "screenshotBtn" + + Layout.alignment: Qt.AlignCenter + preferredSize: btnSize + + normalColor: JamiTheme.screenshotButtonColor + hoveredColor: JamiTheme.screenshotButtonColor + background.opacity: hovered ? 1 : 0.5 + + source: JamiResources.record_round_black_24dp_svg + + imageColor: JamiTheme.whiteColor + imageContainerHeight: 25 + imageContainerWidth: 25 + focusPolicy: Qt.TabFocus + + onClicked: { + root.photo = videoProvider.captureVideoFrame(VideoDevices.getDefaultDevice()); + updateState(RecordBox.States.REC_SUCCESS); + } + } + + PushButton { + id: btnStop + objectName: "btnStop" + + Layout.alignment: Qt.AlignCenter + preferredSize: btnSize + + source: JamiResources.stop_rectangle_24dp_svg + + imageColor: JamiTheme.whiteColor + imageContainerHeight: 20 + imageContainerWidth: 20 + + focusPolicy: Qt.TabFocus + + background: RoundedBorderRectangle { + opacity: btnStop.hovered ? 1 : 0.7 + fillColor: btnStop.hovered ? JamiTheme.recordBoxHoverColor : JamiTheme.recordBoxButtonColor + radius: { + "tl": 5, + "tr": 0, + "br": 0, + "bl": 5 + } + } + + onClicked: { + if (!root.isPhoto) + stopRecording(); + updateState(RecordBox.States.REC_SUCCESS); + } + } + + JamiPushButton { + id: btnRestart + + objectName: "btnRestart" + Layout.alignment: Qt.AlignCenter + preferredSize: btnSize + + source: JamiResources.restart_black_24dp_svg + + imageColor: JamiTheme.whiteColor + imageContainerHeight: 25 + imageContainerWidth: 25 + + focusPolicy: Qt.TabFocus + + background: RoundedBorderRectangle { + opacity: btnRestart.hovered ? 1 : 0.7 + fillColor: btnRestart.hovered ? JamiTheme.recordBoxHoverColor : JamiTheme.recordBoxButtonColor + radius: { + "tl": 5, + "tr": 0, + "br": 0, + "bl": 5 + } + } + + + onClicked: { + if (!root.isPhoto) + stopRecording(); + updateState(RecordBox.States.INIT); + } + } + + JamiPushButton { + id: btnSend + + objectName: "btnSend" + Layout.alignment: Qt.AlignCenter + preferredSize: btnSize + + imageColor: JamiTheme.whiteColor + imageContainerHeight: 25 + imageContainerWidth: 25 + + source: JamiResources.check_circle_24dp_svg + + focusPolicy: Qt.TabFocus + + background: RoundedBorderRectangle { + opacity: btnSend.hovered ? 1 : 0.7 + fillColor: btnSend.hovered ? JamiTheme.recordBoxHoverColor : JamiTheme.recordBoxButtonColor + radius: { + "tl": 0, + "tr": root.isPhoto ? 5 : 0, + "br": root.isPhoto ? 5 : 0, + "bl": 0 + } + } + + onClicked: { + if (!root.isPhoto) { + stopRecording(); + sendRecord(); + } else if (root.photo !== "") { + root.validatePhoto(root.photo); + } + closeRecorder(); + updateState(RecordBox.States.INIT); + } + } + Timer { + id: timer + + interval: 1000 + running: false + repeat: true + onTriggered: updateTimer() + } + + RoundedBorderRectangle { + opacity: 0.7 + fillColor: JamiTheme.recordBoxButtonColor + visible: (!recordButton.visible && !root.isPhoto) || root.isAudio + + Layout.preferredHeight: btnSend.height + Layout.preferredWidth: time.width + 20 + radius: { + "tl": 0, + "tr": 5, + "br": 5, + "bl": 0 + } + + Text { + id: time + + anchors.centerIn: parent + opacity: 1 + + text: "00:00" + color: JamiTheme.whiteColor + font.pointSize: (isVideo ? 12 : 20) + } + } } - - Text { - id: time - - Layout.alignment: Qt.AlignCenter - - visible: !root.isPhoto - text: "00:00" - color: JamiTheme.textColor - font.pointSize: (isVideo ? 12 : 20) - } - } } } + } }