diff --git a/src/contents/ui/CameraPage.qml b/src/contents/ui/CameraPage.qml --- a/src/contents/ui/CameraPage.qml +++ b/src/contents/ui/CameraPage.qml @@ -80,40 +80,41 @@ mainAction: Kirigami.Action { id: captureAction text: { - if (camera.captureMode === Camera.CaptureStillImage) + if (selfTimer.running) + return i18n("Cancel self-timer") + else if (camera.captureMode === Camera.CaptureStillImage) return i18n("Capture photo") else if (camera.videoRecorder.recorderStatus === CameraRecorder.RecordingStatus) return i18n("Stop recording video") else if (camera.captureMode === Camera.CaptureVideo) return i18n("Start recording video") } icon.color: "transparent" icon.name: { - if (camera.captureMode === Camera.CaptureStillImage) + if (selfTimer.running) + return "dialog-error-symbolic" + else if (camera.captureMode === Camera.CaptureStillImage) return "camera-photo-symbolic" else if (camera.videoRecorder.recorderStatus === CameraRecorder.RecordingStatus) return "window-close-symbolic" else if (camera.captureMode === Camera.CaptureVideo) return "emblem-videos-symbolic" } onTriggered: { - if (camera.captureMode === Camera.CaptureStillImage) { - camera.imageCapture.capture() - showPassiveNotification(i18n("Took a photo")) + if (selfTimer.running) { + selfTimer.stop() } - else if (camera.videoRecorder.recorderStatus === CameraRecorder.RecordingStatus) { - camera.videoRecorder.stop() - recordingFeedback.visible = false - showPassiveNotification(i18n("Stopped recording")) + else if ((camera.selfTimerDuration === 0) || (camera.videoRecorder.recorderStatus === CameraRecorder.RecordingStatus)) { + selfTimer.onTriggered() } - else if (camera.captureMode === Camera.CaptureVideo) { - camera.videoRecorder.record() - recordingFeedback.visible = true - showPassiveNotification(i18n("Started recording")) + else { + countdownTimer.remainingSeconds = camera.selfTimerDuration + countdownTimer.start() + selfTimer.start() } } enabled: { - if (camera.captureMode === camera.CaptureStillImage) + if ((camera.captureMode === camera.CaptureStillImage) && !selfTimer.running) return camera.imageCapture.ready else return true @@ -252,6 +253,156 @@ } } + Timer { + id: selfTimer + interval: camera.selfTimerDuration * 1000 + running: false + repeat: false + + onTriggered: { + running = false + + if (camera.captureMode === Camera.CaptureStillImage) { + camera.imageCapture.capture() + showPassiveNotification(i18n("Took a photo")) + } + else if (camera.videoRecorder.recorderStatus === CameraRecorder.RecordingStatus) { + camera.videoRecorder.stop() + recordingFeedback.visible = false + showPassiveNotification(i18n("Stopped recording")) + } + else if (camera.captureMode === Camera.CaptureVideo) { + camera.videoRecorder.record() + recordingFeedback.visible = true + showPassiveNotification(i18n("Started recording")) + } + } + + onRunningChanged: { + if (!running) { + camera.selfTimerRunning = false + selfTimerAnimation.stop() + countdownTimer.stop() + countdownTimer.remainingSeconds = camera.selfTimerDuration + selfTimerIcon.opacity = 1 + } + else { + camera.selfTimerRunning = true + } + } + } + + Timer { // counts the remaining seconds until the selfTimer invokes the capture action + id: countdownTimer + interval: 1000 + running: false + repeat: true + property int remainingSeconds: 0 + + onTriggered: { + remainingSeconds-- + } + } + + RowLayout { + id: selfTimerInfo + visible: !(camera.selfTimerDuration === 0) && !((camera.captureMode === Camera.CaptureVideo) && (camera.videoRecorder.recorderStatus === CameraRecorder.RecordingStatus)) + + anchors { + top: parent.top + horizontalCenter: parent.horizontalCenter + margins: Kirigami.Units.gridUnit * 1 + } + + Kirigami.Icon { + id: selfTimerIcon + source: "alarm-symbolic" + color: selfTimer.running ? "red" : "white" + Layout.preferredWidth: Kirigami.Units.gridUnit + Layout.preferredHeight: Kirigami.Units.gridUnit + Layout.fillWidth: true + Layout.fillHeight: true + Layout.alignment: Qt.AlignCenter + } + + Text { + text: { + if (selfTimer.running) { + "%1 s".arg(countdownTimer.remainingSeconds) + } + else { + "%1 s".arg(camera.selfTimerDuration) + } + } + font.pixelSize: Kirigami.Units.gridUnit + color: { + if (selfTimer.running) { + "red" + } + else { + "white" + } + } + } + + layer.enabled: selfTimerInfo.enabled + layer.effect: DropShadow { + color: Material.dropShadowColor + samples: 30 + spread: 0.5 + } + } + + Rectangle { + id: selfTimerRectangle + visible: selfTimer.running + color: "transparent" + border.color: "red" + border.width: Kirigami.Units.gridUnit / 6 + opacity: 0 + + anchors { + fill: parent + centerIn: parent + } + } + + SequentialAnimation { + id: selfTimerAnimation + running: selfTimer.running + loops: Animation.Infinite + + ParallelAnimation { + OpacityAnimator { + target: selfTimerIcon + from: 0 + to: 1 + duration: 500 + } + OpacityAnimator { + target: selfTimerRectangle + from: 0 + to: 1 + duration: 500 + } + } + + ParallelAnimation{ + OpacityAnimator { + target: selfTimerIcon + from: 1 + to: 0 + duration: 500 + } + OpacityAnimator { + target: selfTimerRectangle + from: 1 + to: 0 + duration: 500 + } + } + } + PreviewArea { imageCapture: camera.imageCapture diff --git a/src/contents/ui/GlobalDrawer.qml b/src/contents/ui/GlobalDrawer.qml --- a/src/contents/ui/GlobalDrawer.qml +++ b/src/contents/ui/GlobalDrawer.qml @@ -137,9 +137,35 @@ onTriggered: settings.whiteBalanceMode = CameraImageProcessing.WhiteBalanceFluorescent text: i18n("Fluorescent") } - }, - Kirigami.Action { - text: i18n("About") + }, + Kirigami.Action { + text: i18n("Self-timer") + iconName: "clock" + enabled: !camera.selfTimerRunning + + Kirigami.Action { + text: i18n("Off") + onTriggered: camera.selfTimerDuration = 0 + } + Kirigami.Action { + text: i18n("2 s") + onTriggered: camera.selfTimerDuration = 2 + } + Kirigami.Action { + text: i18n("5 s") + onTriggered: camera.selfTimerDuration = 5 + } + Kirigami.Action { + text: i18n("10 s") + onTriggered: camera.selfTimerDuration = 10 + } + Kirigami.Action { + text: i18n("20 s") + onTriggered: camera.selfTimerDuration = 20 + } + }, + Kirigami.Action { + text: i18n("About") iconName: "help-about" onTriggered: { while (pageStack.depth > 1) diff --git a/src/contents/ui/main.qml b/src/contents/ui/main.qml --- a/src/contents/ui/main.qml +++ b/src/contents/ui/main.qml @@ -77,6 +77,9 @@ deviceId: settings.cameraDeviceId imageProcessing.whiteBalanceMode: settings.whiteBalanceMode + property int selfTimerDuration: 0 // in seconds + property bool selfTimerRunning: false + imageCapture { id: imageCapture resolution: settings.resolution