blob: 730abc2dfb7d6a54861f429a4d13770014d96d42 [file] [log] [blame]
/*
* Copyright (C) 2020 by Savoir-faire Linux
* Author: Albert BabĂ­ <albert.babi@savoirfairelinux.com>
*
* 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 <https://www.gnu.org/licenses/>.
*/
import QtQuick 2.15
import QtQuick.Controls 2.14
import QtQuick.Layouts 1.14
import QtQuick.Controls.Styles 1.4
import QtQuick.Dialogs 1.3
import net.jami.Models 1.0
import QtGraphicalEffects 1.15
import QtQuick.Shapes 1.15
import "../../commoncomponents"
Rectangle {
enum States {
INIT,
RECORDING,
REC_SUCCESS
}
id: recBox
color: "#FFFFFF"
width: 320
height: 240
radius: 5
border.color: JamiTheme.tabbarBorderColor
property string pathRecorder: ""
property string timeText: "00:00"
property int duration: 0
property int state: RecordBox.States.INIT
property bool isVideo: false
property bool previewAvailable: false
property int preferredWidth: 320
property int preferredHeight: 240
property int btnSize: 40
property int offset: 3
property int curveRadius: 6
property int x_offset: 0
property int y_offset: 0
function openRecorder(set_x, set_y, vid) {
focus = true
visible = true
isVideo = vid
x_offset = (isVideo ? -34 : -80)
scaleHeight()
y_offset = -64-height
updateState(RecordBox.States.INIT)
if (isVideo){
ClientWrapper.accountAdaptor.startPreviewing(false)
previewAvailable = true
}
}
function scaleHeight(){
height = preferredHeight
if (isVideo) {
var device = ClientWrapper.avmodel.getDefaultDevice()
var settings = SettingsAdapter.get_Video_Settings_Size(device)
var res = settings.split("x")
var aspectRatio = res[1] / res[0]
if (aspectRatio) {
height = preferredWidth*aspectRatio
} else {
console.error("Could not scale recording video preview")
}
}
}
onActiveFocusChanged: {
if (visible) {
closeRecorder()
}
}
onVisibleChanged: {
if (!visible) {
closeRecorder()
}
}
function closeRecorder() {
if (isVideo && ClientWrapper.accountAdaptor.isPreviewing()) {
ClientWrapper.accountAdaptor.stopPreviewing()
}
stopRecording()
visible = false
}
function updateState(new_state) {
state = new_state
recordButton.visible = (state == RecordBox.States.INIT)
btnStop.visible = (state == RecordBox.States.RECORDING)
btnRestart.visible = (state == RecordBox.States.REC_SUCCESS)
btnSend.visible = (state == RecordBox.States.REC_SUCCESS)
if (state == RecordBox.States.INIT) {
duration = 0
time.text = "00:00"
timer.stop()
} else if (state == RecordBox.States.REC_SUCCESS) {
timer.stop()
}
}
function startRecording() {
timer.start()
pathRecorder = ClientWrapper.avmodel.startLocalRecorder(!isVideo)
if (pathRecorder == "") {
timer.stop()
}
}
function stopRecording() {
if (pathRecorder !== "") {
ClientWrapper.avmodel.stopLocalRecorder(pathRecorder)
}
}
function sendRecord() {
if (pathRecorder !== "") {
MessagesAdapter.sendFile(pathRecorder)
}
}
function updateTimer() {
duration += 1
var m = Math.trunc(duration / 60)
var s = (duration % 60)
var min = (m < 10) ? "0" + String(m) : String(m)
var sec = (s < 10) ? "0" + String(s) : String(s)
time.text = min + ":" + sec;
}
Connections{
target: ClientWrapper.renderManager
}
Shape {
id: backgroundShape
width: recBox.width
height: recBox.height
anchors.centerIn: parent
x: -offset
y: -offset
ShapePath {
fillColor: "white"
strokeWidth: 1
strokeColor: JamiTheme.tabbarBorderColor
startX: -offset+curveRadius; startY: -offset
joinStyle: ShapePath.RoundJoin
PathLine { x: width+offset-curveRadius; y: -offset }
PathArc {
x: width+offset; y: -offset+curveRadius
radiusX: curveRadius; radiusY: curveRadius
}
PathLine { x: width+offset; y: height+offset-curveRadius }
PathArc {
x: width+offset-curveRadius; y: height+offset
radiusX: curveRadius; radiusY: curveRadius
}
PathLine { x: width/2+10; y: height+offset }
PathLine { x: width/2; y: height+offset+10 }
PathLine { x: width/2-10; y: height+offset }
PathLine { x: -offset+curveRadius; y: height+offset }
PathArc {
x: -offset; y: height+offset-curveRadius
radiusX: curveRadius; radiusY: curveRadius
}
PathLine { x: -offset; y: -offset+curveRadius }
PathArc {
x: -offset+curveRadius; y: -offset
radiusX: curveRadius; radiusY: curveRadius
}
}
}
Rectangle {
id: rectBox
visible: (isVideo && previewAvailable)
Layout.alignment: Qt.AlignHCenter
anchors.fill: parent
color: "black"
radius: 5
PreviewRenderer{
id: previewWidget
anchors.fill: rectBox
anchors.centerIn: rectBox
layer.enabled: true
layer.effect: OpacityMask {
maskSource: rectBox
}
}
}
Label {
visible: (isVideo && !previewAvailable)
Layout.fillWidth: true
Layout.alignment: Qt.AlignCenter
text: qsTr("Preview unavailable")
font.pointSize: 10
font.kerning: true
}
Timer {
id: timer
interval: 1000;
running: false;
repeat: true
onTriggered: updateTimer()
}
Text {
id: time
visible: true
text: "00:00"
color: (isVideo ? "white" : "black")
font.pointSize: (isVideo ? 12 : 20)
anchors.centerIn: recordButton
anchors.horizontalCenterOffset: (isVideo ? 100 : 0)
anchors.verticalCenterOffset: (isVideo ? 0 : -100)
}
HoverableRadiusButton {
id: recordButton
width: btnSize
height: btnSize
anchors.horizontalCenter: recBox.horizontalCenter
anchors.bottom: recBox.bottom
anchors.bottomMargin: 5
buttonImageHeight: height
buttonImageWidth: height
backgroundColor: isVideo? "#000000cc" : "white"
radius: height / 2
icon.source: "qrc:/images/icons/av_icons/fiber_manual_record-24px.svg"
icon.height: 24
icon.width: 24
icon.color: "#dc2719"
onClicked: {
updateState(RecordBox.States.RECORDING)
startRecording()
}
}
HoverableRadiusButton {
id: btnStop
width: btnSize
height: btnSize
anchors.horizontalCenter: recBox.horizontalCenter
anchors.bottom: recBox.bottom
anchors.bottomMargin: 5
buttonImageHeight: height
buttonImageWidth: height
backgroundColor: isVideo? "#000000cc" : "white"
radius: height / 2
icon.source: "qrc:/images/icons/av_icons/stop-24px-red.svg"
icon.height: 24
icon.width: 24
icon.color: isVideo? "white" : "black"
onClicked: {
stopRecording()
updateState(RecordBox.States.REC_SUCCESS)
}
}
HoverableRadiusButton {
id: btnRestart
width: btnSize
height: btnSize
anchors.horizontalCenter: recBox.horizontalCenter
anchors.horizontalCenterOffset: -25
anchors.bottom: recBox.bottom
anchors.bottomMargin: 5
buttonImageHeight: height
buttonImageWidth: height
backgroundColor: isVideo? "#000000cc" : "white"
radius: height / 2
icon.source: "qrc:/images/icons/av_icons/re-record-24px.svg"
icon.height: 24
icon.width: 24
icon.color: isVideo? "white" : "black"
onClicked: {
stopRecording()
updateState(RecordBox.States.INIT)
}
}
HoverableRadiusButton {
id: btnSend
width: btnSize
height: btnSize
anchors.horizontalCenter: recBox.horizontalCenter
anchors.horizontalCenterOffset: 25
anchors.bottom: parent.bottom
anchors.bottomMargin: 5
buttonImageHeight: height
buttonImageWidth: height
backgroundColor: isVideo? "#000000cc" : "white"
radius: height / 2
icon.source: "qrc:/images/icons/av_icons/send-24px.svg"
icon.height: 24
icon.width: 24
icon.color: isVideo? "white" : "black"
onClicked: {
stopRecording()
sendRecord()
closeRecorder()
updateState(RecordBox.States.INIT)
}
}
}