Browse Source

[feature] - Add new ‘showRecordingLength’ option for the Webcam plugin (#1947)

* [feature] - Add new ‘showRecordingLength’ prop for the Webcam plugin. When this is true, it counts the duration of a recording and displays it to the user. Add a test for generating the correct duration of the recording.

* Update packages/@uppy/webcam/src/style.scss

Co-Authored-By: Artur Paikin <artur@arturpaikin.com>

* Added i18n for the recording length counter and update Readme. Fix Webcam styles where some styles were not in alphabetical order.

* Update packages/@uppy/webcam/src/style.scss

Co-Authored-By: Artur Paikin <artur@arturpaikin.com>

Added i18n for the recording length counter and update Readme. Fix Webcam styles where some styles were not in alphabetical order.
Dominic Eden 5 years ago
parent
commit
e7fbaa940d

+ 1 - 0
packages/@uppy/locales/src/de_DE.js

@@ -73,6 +73,7 @@ de_DE.strings = {
     '1': '%{smart_count} Dateien verarbeiten',
     '2': '%{smart_count} Dateien verarbeiten'
   },
+  recordingLength: 'Aufnahmedauer %{recording_length}',
   removeFile: 'Datei entfernen',
   resetFilter: 'Filter zurücksetzen',
   resume: 'Fortsetzen',

+ 1 - 0
packages/@uppy/locales/src/en_US.js

@@ -75,6 +75,7 @@ en_US.strings = {
     '1': 'Processing %{smart_count} files',
     '2': 'Processing %{smart_count} files'
   },
+  recordingLength: 'Recording length %{recording_length}',
   removeFile: 'Remove file',
   resetFilter: 'Reset filter',
   resume: 'Resume',

+ 1 - 0
packages/@uppy/locales/src/es_ES.js

@@ -72,6 +72,7 @@ es_ES.strings = {
     '1': 'Procesando %{smart_count} archivos',
     '2': 'Procesando %{smart_count} archivos'
   },
+  recordingLength: 'Duración de grabación %{recording_length}',
   removeFile: 'Eliminar archivo',
   resetFilter: 'Limpiar filtro',
   resume: 'Reanudar',

+ 1 - 0
packages/@uppy/locales/src/fr_FR.js

@@ -72,6 +72,7 @@ fr_FR.strings = {
     '1': 'Traitement de %{smart_count} fichiers',
     '2': 'Traitement de %{smart_count} fichiers'
   },
+  recordingLength: 'Durée d\'enregistrement %{recording_length}',
   removeFile: 'Effacer le fichier',
   resetFilter: 'Réinitialiser filtre',
   resume: 'Continuer',

+ 1 - 0
packages/@uppy/locales/src/nl_NL.js

@@ -72,6 +72,7 @@ nl_NL.strings = {
     '1': 'Bezig met %{smart_count} bestanden te verwerken',
     '2': 'Bezig met %{smart_count} bestanden te verwerken'
   },
+  recordingLength: 'Opnameduur %{recording_length}',
   removeFile: 'Bestand verwijderen',
   resetFilter: 'Filter resetten',
   resume: 'Hervatten',

+ 2 - 1
packages/@uppy/webcam/README.md

@@ -18,7 +18,8 @@ const Webcam = require('@uppy/webcam')
 const uppy = Uppy()
 uppy.use(Webcam, {
   mirror: true,
-  facingMode: 'user'
+  facingMode: 'user',
+  showRecordingLength: true
 })
 ```
 

+ 4 - 0
packages/@uppy/webcam/src/CameraScreen.js

@@ -1,6 +1,7 @@
 const { h, Component } = require('preact')
 const SnapshotButton = require('./SnapshotButton')
 const RecordButton = require('./RecordButton')
+const RecordingLength = require('./RecordingLength')
 
 function isModeAvailable (modes, mode) {
   return modes.indexOf(mode) !== -1
@@ -22,6 +23,7 @@ class CameraScreen extends Component {
       isModeAvailable(this.props.modes, 'video-audio')
     )
     const shouldShowSnapshotButton = isModeAvailable(this.props.modes, 'picture')
+    const shouldShowRecordingLength = this.props.supportsRecording && this.props.showRecordingLength
 
     return (
       <div class="uppy uppy-Webcam-container">
@@ -29,6 +31,8 @@ class CameraScreen extends Component {
           <video class={`uppy-Webcam-video  ${this.props.mirror ? 'uppy-Webcam-video--mirrored' : ''}`} autoplay muted playsinline srcObject={this.props.src || ''} />
         </div>
         <div class="uppy-Webcam-buttonContainer">
+          {shouldShowRecordingLength ? RecordingLength(this.props) : null}
+          {' '}
           {shouldShowSnapshotButton ? SnapshotButton(this.props) : null}
           {' '}
           {shouldShowRecordButton ? RecordButton(this.props) : null}

+ 12 - 0
packages/@uppy/webcam/src/RecordingLength.js

@@ -0,0 +1,12 @@
+const { h } = require('preact')
+const formatSeconds = require('./formatSeconds')
+
+module.exports = function RecordingLength ({ recordingLengthSeconds, i18n }) {
+  const formattedRecordingLengthSeconds = formatSeconds(recordingLengthSeconds)
+
+  return (
+    <div class="uppy-Webcam-recordingLength" aria-label={i18n('recordingLength', { recording_length: formattedRecordingLengthSeconds })}>
+      {formattedRecordingLengthSeconds}
+    </div>
+  )
+}

+ 12 - 0
packages/@uppy/webcam/src/formatSeconds.js

@@ -0,0 +1,12 @@
+/**
+ * Takes an Integer value of seconds (e.g. 83) and converts it into a human-readable formatted string (e.g. '1:23').
+ *
+ * @param {Integer} seconds
+ * @returns {string} the formatted seconds (e.g. '1:23' for 1 minute and 23 seconds)
+ *
+ */
+module.exports = function formatSeconds (seconds) {
+  return `${Math.floor(
+        seconds / 60
+      )}:${String(seconds % 60).padStart(2, 0)}`
+}

+ 11 - 0
packages/@uppy/webcam/src/formatSeconds.test.js

@@ -0,0 +1,11 @@
+const formatSeconds = require('./formatSeconds')
+
+describe('formatSeconds', () => {
+  it('should return a value of \'0:43\' when an argument of 43 seconds is supplied', () => {
+    expect(formatSeconds(43)).toEqual('0:43')
+  })
+
+  it('should return a value of \'1:43\' when an argument of 103 seconds is supplied', () => {
+    expect(formatSeconds(103)).toEqual('1:43')
+  })
+})

+ 21 - 3
packages/@uppy/webcam/src/index.js

@@ -54,7 +54,8 @@ module.exports = class Webcam extends Plugin {
         startRecording: 'Begin video recording',
         stopRecording: 'Stop video recording',
         allowAccessTitle: 'Please allow access to your camera',
-        allowAccessDescription: 'In order to take pictures or record video with your camera, please allow camera access for this site.'
+        allowAccessDescription: 'In order to take pictures or record video with your camera, please allow camera access for this site.',
+        recordingLength: 'Recording length %{recording_length}'
       }
     }
 
@@ -70,7 +71,8 @@ module.exports = class Webcam extends Plugin {
       ],
       mirror: true,
       facingMode: 'user',
-      preferredVideoMimeType: null
+      preferredVideoMimeType: null,
+      showRecordingLength: false
     }
 
     this.opts = { ...defaultOptions, ...opts }
@@ -169,6 +171,14 @@ module.exports = class Webcam extends Plugin {
     })
     this.recorder.start()
 
+    if (this.opts.showRecordingLength) {
+      // Start the recordingLengthTimer if we are showing the recording length.
+      this.recordingLengthTimer = setInterval(() => {
+        const currentRecordingLength = this.getPluginState().recordingLengthSeconds
+        this.setPluginState({ recordingLengthSeconds: currentRecordingLength + 1 })
+      }, 1000)
+    }
+
     this.setPluginState({
       isRecording: true
     })
@@ -180,6 +190,12 @@ module.exports = class Webcam extends Plugin {
         resolve()
       })
       this.recorder.stop()
+
+      if (this.opts.showRecordingLength) {
+        // Stop the recordingLengthTimer if we are showing the recording length.
+        clearInterval(this.recordingLengthTimer)
+        this.setPluginState({ recordingLengthSeconds: 0 })
+      }
     })
 
     return stopped.then(() => {
@@ -368,6 +384,7 @@ module.exports = class Webcam extends Plugin {
         onStop={this.stop}
         i18n={this.i18n}
         modes={this.opts.modes}
+        showRecordingLength={this.opts.showRecordingLength}
         supportsRecording={supportsMediaRecorder()}
         recording={webcamState.isRecording}
         mirror={this.opts.mirror}
@@ -378,7 +395,8 @@ module.exports = class Webcam extends Plugin {
 
   install () {
     this.setPluginState({
-      cameraReady: false
+      cameraReady: false,
+      recordingLengthSeconds: 0
     })
 
     const target = this.opts.target

+ 19 - 12
packages/@uppy/webcam/src/style.scss

@@ -105,18 +105,6 @@
   line-height: 1.3;
 }
 
-.uppy-Webcam-title {
-  font-size: 22px;
-  line-height: 1.35;
-  font-weight: 400;
-  margin: 0;
-  margin-bottom: 5px;
-  padding: 0 15px;
-  max-width: 500px;
-  text-align: center;
-  color: $gray-800;
-}
-
 .uppy-Webcam-permissons p {
   text-align: center;
   line-height: 1.45;
@@ -130,3 +118,22 @@
   color: $gray-400;
   margin-bottom: 30px;
 }
+
+.uppy-Webcam-recordingLength {
+  position: absolute;
+  right: 20px;
+  color: $gray-600;
+  font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
+}
+
+.uppy-Webcam-title {
+  font-size: 22px;
+  line-height: 1.35;
+  font-weight: 400;
+  margin: 0;
+  margin-bottom: 5px;
+  padding: 0 15px;
+  max-width: 500px;
+  text-align: center;
+  color: $gray-800;
+}

+ 8 - 0
website/src/docs/webcam.md

@@ -65,6 +65,7 @@ uppy.use(Webcam, {
   ],
   mirror: true,
   facingMode: 'user',
+  showRecordingLength: false,
   locale: {}
 })
 ```
@@ -113,6 +114,10 @@ Devices sometimes have multiple cameras, front and back, for example. There is a
 - `left`: The video source is facing toward the user but to their left, such as a camera aimed toward the user but over their left shoulder.
 - `right`: The video source is facing toward the user but to their right, such as a camera aimed toward the user but over their right shoulder.
 
+### `showRecordingLength: false`
+
+Configures whether or not to show the length of the recording while the recording is in progress. The default is `false`.
+
 ### `preferredVideoMimeType: null`
 
 Set the preferred mime type for video recordings, for example `'video/webm'`. If the browser supports the given mime type, the video will be recorded in this format. If the browser does not support it, it will use the browser default.
@@ -136,6 +141,9 @@ strings: {
   // Used as the label for the button that stops a video recording.
   // This is not visibly rendered but is picked up by screen readers.
   stopRecording: 'Stop video recording',
+  // Used as the label for the recording length counter. See the showRecordingLength option.
+  // This is not visibly rendered but is picked up by screen readers.
+  recordingLength: 'Recording length %{recording_length}',
   // Title on the “allow access” screen
   allowAccessTitle: 'Please allow access to your camera',
   // Description on the “allow access” screen