added error handling. this TODO has been completed
[harmattan/cameraplus] / qml / RecordingPage.qml
1 // -*- qml -*-
2
3 /*!
4  * This file is part of CameraPlus.
5  *
6  * Copyright (C) 2012 Mohammed Sameer <msameer@foolab.org>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21  */
22
23 import QtQuick 1.1
24 import com.nokia.meego 1.1
25 import QtCamera 1.0
26 import CameraPlus 1.0
27 import "data.js" as Data
28
29 // TODO: losing resources in the middle of recording will produce corrupted video
30 // TODO: optional resources?
31
32 CameraPage {
33         id: page
34         modesVisible: false
35         property bool error: false
36
37         policyMode: CameraResources.Recording
38
39         controlsVisible: cam.running && videoMode.recording && !cameraMode.animationRunning && !previewAnimationRunning && !error
40
41         orientationLock: PageOrientation.LockLandscape
42
43         function policyLost() {
44                 page.stopRecording();
45         }
46
47         function cameraError() {
48                 error = true;
49                 page.stopRecording();
50         }
51
52         Component.onDestruction: videoMode.stopRecording();
53
54         onStatusChanged: {
55                 if (page.status == PageStatus.Active) {
56                         startRecording();
57                 }
58         }
59
60         function startRecording() {
61                 if (!pipelineManager.acquired || pipelineManager.hijacked) {
62                         showError(qsTr("Failed to acquire needed resources."));
63                         pageStack.pop(undefined, true);
64                         return;
65                 }
66
67                 metaData.setMetaData();
68
69                 if (!mountProtector.lock()) {
70                         showError(qsTr("Failed to lock images directory."));
71                         pageStack.pop(undefined, true);
72                         return;
73                 }
74
75                 var file = fileNaming.videoFileName();
76                 var tmpFile = fileNaming.temporaryVideoFileName();
77
78                 if (!videoMode.startRecording(file, tmpFile)) {
79                         showError(qsTr("Failed to record video. Please restart the camera."));
80                         pageStack.pop(undefined, true);
81                         mountProtector.unlock();
82                 }
83
84                 // TODO: sometimes this fails (fast stop after start).
85                 trackerStore.storeVideo(file);
86         }
87
88         function stopRecording() {
89                 mountProtector.unlock();
90                 // Something is fishy here but if there is an error
91                 // and we use immediate mode then the page never gets destroyed.
92                 pageStack.pop(undefined, error ? false : true);
93         }
94
95         DisplayState {
96                 inhibitDim: true
97         }
98
99         onBatteryLow: {
100                 if (!checkBattery()) {
101                         page.stopRecording();
102                         showError(qsTr("Not enough battery to record video."));
103                 }
104         }
105
106         CaptureButton {
107                 id: recording
108                 anchors.right: parent.right
109                 anchors.rightMargin: 20
110                 anchors.verticalCenter: parent.verticalCenter
111                 iconSource: "image://theme/icon-m-camera-video-record"
112                 width: 75
113                 height: 75
114                 opacity: 0.5
115
116                 onClicked: page.stopRecording();
117                 visible: controlsVisible
118         }
119
120         Connections {
121                 target: Qt.application
122                 onActiveChanged: {
123                         if (!Qt.application.active) {
124                                 page.stopRecording();
125                         }
126                 }
127         }
128
129         VideoMode {
130                 id: videoMode
131                 camera: cam
132         }
133
134         VideoTorchButton {
135                 id: torch
136                 camera: cam
137                 visible: controlsVisible
138                 anchors.top: parent.top
139                 anchors.left: parent.left
140                 anchors.topMargin: 20
141                 anchors.leftMargin: 20
142                 opacity: 0.5
143         }
144
145         VideoEvCompButton {
146                 id: evComp
147                 visible: controlsVisible
148                 anchors.top: torch.bottom
149                 anchors.left: parent.left
150                 anchors.topMargin: 10
151                 anchors.leftMargin: 20
152         }
153
154         Rectangle {
155                 anchors.left: parent.left
156                 anchors.bottom: parent.bottom
157                 anchors.leftMargin: 20
158                 anchors.bottomMargin: 20
159
160                 visible: controlsVisible
161
162                 color: "black"
163                 opacity: 0.5
164                 width: 100
165                 height: 30
166
167                 Timer {
168                         id: recordingDuration
169
170                         property int duration: 0
171
172                         running: videoMode.recording
173                         interval: 1000
174                         repeat: true
175
176                         onTriggered: {
177                                 duration = duration + 1;
178                                 if (duration == 3600) {
179                                         page.stopRecording();
180                                         showError(qsTr("Maximum recording time reached."));
181                                 }
182                                 else if (!checkDiskSpace()) {
183                                         page.stopRecording();
184                                         showError(qsTr("Not enough space to continue recording."));
185                                 }
186                         }
187                 }
188
189                 Image {
190                         id: recordingIcon
191                         source: "image://theme/icon-m-camera-ongoing-recording"
192                         width: 20
193                         height: 20
194                         anchors.verticalCenter: parent.verticalCenter
195                         anchors.left: parent.left
196                         anchors.leftMargin: 5
197                         sourceSize.width: 20
198                         sourceSize.height: 20
199                 }
200
201                 Label {
202                         function formatDuration(dur) {
203                                 var secs = parseInt(recordingDuration.duration);
204                                 var minutes = Math.floor(secs / 60);
205                                 var seconds = secs - (minutes * 60);
206
207                                 var date = new Date();
208                                 date.setSeconds(seconds);
209                                 date.setMinutes(minutes);
210                                 return Qt.formatTime(date, "mm:ss");
211                         }
212
213                         id: durationLabel
214                         text: formatDuration(recordingDuration.duration);
215                         anchors.left: recordingIcon.right
216                         anchors.leftMargin: 5
217                 }
218         }
219 }