QuickUploader.vue 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. <template>
  2. <div id="quick-uploader">
  3. <!-- static landing UI -->
  4. <div v-show="!(showStream && canStream)" class="container has-text-centered">
  5. <div class="columns quick-uploader">
  6. <!-- trailer phrase that invite to add an account -->
  7. <div class="column is-full quick-uploader-header" :class="{ 'is-invisible' : !showTrailer }">
  8. {{ $t('twofaccounts.no_account_here') }}<br>
  9. {{ $t('twofaccounts.add_first_account') }}
  10. </div>
  11. <!-- add button -->
  12. <div class="column is-full quick-uploader-button" >
  13. <div class="quick-uploader-centerer">
  14. <!-- scan button that launch camera stream -->
  15. <label v-if="canStream" class="button is-link is-medium is-rounded is-focused" @click="enableStream()">
  16. {{ $t('twofaccounts.forms.scan_qrcode') }}
  17. </label>
  18. <!-- or classic input field -->
  19. <form v-else @submit.prevent="createAccount" @keydown="form.onKeydown($event)">
  20. <label :class="{'is-loading' : form.isBusy}" class="button is-link is-medium is-rounded is-focused">
  21. <input v-if="$root.appSettings.useBasicQrcodeReader" class="file-input" type="file" accept="image/*" v-on:change="uploadQrcode" ref="qrcodeInput">
  22. <qrcode-capture v-else @decode="uploadQrcode" class="file-input" ref="qrcodeInput" />
  23. {{ $t('twofaccounts.forms.use_qrcode.val') }}
  24. </label>
  25. <field-error :form="form" field="qrcode" />
  26. <field-error :form="form" field="uri" />
  27. </form>
  28. </div>
  29. </div>
  30. <!-- Fallback link to classic form -->
  31. <div class="column is-full quick-uploader-footer">
  32. <router-link :to="{ name: 'create' }" class="is-link">{{ $t('twofaccounts.use_full_form') }}</router-link>
  33. </div>
  34. <div v-if="showError" class="column is-full quick-uploader-footer">
  35. <notification :message="errorText" :isDeletable="false" type="is-danger" />
  36. </div>
  37. </div>
  38. </div>
  39. <!-- camera stream fullscreen scanner -->
  40. <div v-show="showStream && canStream">
  41. <div class="fullscreen-alert has-text-centered">
  42. <span class="is-size-4 has-text-light">
  43. <font-awesome-icon :icon="['fas', 'spinner']" size="2x" spin />
  44. </span>
  45. </div>
  46. <div class="fullscreen-streamer">
  47. <qrcode-stream @decode="uploadQrcode" @init="onStreamerInit" :camera="camera" />
  48. </div>
  49. <div class="fullscreen-footer">
  50. <!-- Cancel button -->
  51. <label class="button is-large is-warning is-rounded" @click="disableStream()">
  52. {{ $t('commons.cancel') }}
  53. </label>
  54. </div>
  55. </div>
  56. </div>
  57. </template>
  58. <script>
  59. import Form from './Form'
  60. export default {
  61. name: 'QuickUploader',
  62. data(){
  63. return {
  64. form: new Form({
  65. qrcode: null,
  66. uri: '',
  67. }),
  68. errorName: '',
  69. errorText: '',
  70. showStream: false,
  71. canStream: true,
  72. camera: 'auto',
  73. }
  74. },
  75. computed: {
  76. debugMode: function() {
  77. return process.env.NODE_ENV
  78. },
  79. showError: function() {
  80. return this.debugMode == 'development' && this.errorName == 'NotAllowedError'
  81. },
  82. },
  83. props: {
  84. showTrailer: {
  85. type: Boolean,
  86. default: false
  87. },
  88. directStreaming: {
  89. type: Boolean,
  90. default: true
  91. },
  92. },
  93. created() {
  94. if( this.$root.appSettings.useBasicQrcodeReader ) {
  95. // User has set the basic QR code reader so we disable the modern one
  96. this.canStream = this.showStream = false
  97. }
  98. else {
  99. if( this.directStreaming ) {
  100. this.enableStream()
  101. }
  102. }
  103. },
  104. beforeDestroy() {
  105. this.form.clear()
  106. },
  107. methods: {
  108. async enableStream() {
  109. this.$parent.$emit('initStreaming')
  110. this.camera = 'auto'
  111. this.showStream = true
  112. console.log('stream enabled')
  113. },
  114. async disableStream() {
  115. this.camera = 'off'
  116. this.showStream = false
  117. this.$parent.$emit('stopStreaming')
  118. },
  119. async onStreamerInit (promise) {
  120. this.errorText = ''
  121. this.errorName = ''
  122. try {
  123. await promise
  124. }
  125. catch (error) {
  126. this.errorName = error.name
  127. if (error.name === 'NotAllowedError') {
  128. this.errorText = this.$t('twofaccounts.stream.need_grant_permission')
  129. } else if (error.name === 'NotReadableError') {
  130. this.errorText = this.$t('twofaccounts.stream.not_readable')
  131. } else if (error.name === 'NotFoundError') {
  132. this.errorText = this.$t('twofaccounts.stream.no_cam_on_device')
  133. } else if (error.name === 'NotSupportedError' || error.name === 'InsecureContextError') {
  134. this.errorText = this.$t('twofaccounts.stream.secured_context_required')
  135. } else if (error.name === 'OverconstrainedError') {
  136. this.errorText = this.$t('twofaccounts.stream.camera_not_suitable')
  137. } else if (error.name === 'StreamApiNotSupportedError') {
  138. this.errorText = this.$t('twofaccounts.stream.stream_api_not_supported')
  139. }
  140. }
  141. this.setUploader()
  142. },
  143. setUploader() {
  144. if( this.errorName ) {
  145. this.canStream = false
  146. console.log(this.errorText)
  147. }
  148. if( !this.errorName && !this.showStream ) {
  149. this.camera = 'off'
  150. }
  151. if( this.canStream && this.showStream) {
  152. this.$parent.$emit('startStreaming')
  153. }
  154. },
  155. async uploadQrcode(event) {
  156. var response
  157. if(this.$root.appSettings.useBasicQrcodeReader) {
  158. let imgdata = new FormData();
  159. imgdata.append('qrcode', this.$refs.qrcodeInput.files[0]);
  160. response = await this.form.upload('/api/qrcode/decode', imgdata)
  161. }
  162. else {
  163. // We post the decoded URI instead of an image to decode
  164. this.form.uri = event
  165. if( !this.form.uri ) {
  166. return false
  167. }
  168. response = await this.form.post('/api/qrcode/decode')
  169. }
  170. this.$router.push({ name: 'create', params: { qrAccount: response.data } });
  171. },
  172. }
  173. };
  174. </script>