bitpay / cordova-plugin-qrscanner

A fast, energy efficient, highly-configurable QR code scanner for Cordova apps and the browser.
MIT License
575 stars 783 forks source link

Ionic ver1 camera view not displaying, other verX methods not working #312

Open rolinger opened 4 years ago

rolinger commented 4 years ago

So far, I am only testing my Ionic v1 app on Android. I am using Ionic's tabs and on one tab server based content is loaded with an ng-repeat. At the top is a button to scan a QR Code, the button click initializes $scope.scannerOpen() and should show the scanner with this functions:

  $scope.scannerOpen = function() {
    QRScanner.prepare(onDone) ; // prepare the camera, check permissions
  }

  function onDone(err, status){
    if (err) {
     // here we can handle errors and clean up any loose ends.
     console.error("Camera: Prepare error - " +err);
     return ;
    }
    $scope.scannerStatus() ;
  }  
  $scope.scannerStatus = function() {
    QRScanner.getStatus(function(status){
      if (status.authorized) { // authorized, show scanner 
        console.log("camera: authorized") ;
        $scope.scannerShow() ;
      } else if (!status.authorized && !status.denied) { // never asked, prompt user
        console.log("camera: never asked") ;
        QRScanner.prepare(onDone) ;
      } else if (status.denied && status.canOpenSettings) { // user previously denied prompt, ask user to change settings
        console.log("camera: denied") ;
        QRScanner.openSettings() ;
      } else if (status.restricted) {  // phone settings restricted
        console.log("camera: restricted") ;      
        alert("Camera is restricted, unable to ask for permissions or display phone camera settings.")
      }
    });  
  }

  $scope.scannerShow = function() {
    // Make the webview transparent so the video preview is visible behind it.
    console.log("Camera: Show Scanner") ;
    QRScanner.show();
  }

My console is showing me AUTHORIZED and SHOW SCANNER - but the camera scanner does not display. I then went through my rendered dom and applied background:transparent to the BODY, ION-VIEW, ION-NAV-VIEW, ION-CONTENT - basically any element that took up the whole display. But nothing worked or revealed the camera underneath.

What am I missing here?

Because I have gone through all major elements in the rendered DOM and added background:transparent and I am still not seeing the scanner I am not even certain if the scanner is there or not.

NOTE 1: One thing I noticed about the QRSCanner.show() function is that contrary to what the API documentation says transparency is NOT added to the BODY or other elements it claims it does - at least not for an Ionic v1 Tabs app.

NOTE 2: Adding transparency to the <ion-app> element seems to be the main solution for other Ionic verX apps, however in an Ionic v1 App, there is no <ion-app> element - it requires a different method. I haven't found one, so I had to create something that manipulated the DOM by turning on/off various element transparency/displays - but you must turn off what your turned on before you leave the tab view - or those changes will show in other tab views.

rolinger commented 4 years ago

On a whim, I tried blindly scanning a qrcode and to my surprise it worked! Thats great - but I still can't figure out why its not displaying. I have gone through the DOM again applying background: none transparent everywhere I can think of (and not think of) and the scanner view is still not displaying.

rolinger commented 4 years ago

Ok...I found 3 elements that need to be altered. However, I can't imagine this is the final solution. Two of which I had to add background: none transparent to Ionic created elements, and then i had to add display:none to the actual <ion-content> tag. Including a screen shot of the code where I had to add these CSS tags.

image

I can control the <ion-view> and the <ion-content> via element IDs. However, the first DIV element that needs transparency I cannot add an ID to. It is auto-created by IONIC during the launch and it has no ID. I have tried messing with the class pane and i can get it to work, but then that messes with MANY other elements that use the class pane - all of this is creating an enormous amount of overhead work that I have to apply and un-apply everytime I need the scanner to start/stop.

rolinger commented 4 years ago

For anyone that cares, I had to do some elaborate stuff to make this work cleanly in an Ionic v1 app. And "cleanly" is quite subjective here! PLEASE - if there is a more simple solution please share. I added a frame box with a centering red line through the box around the scanning view screen. If you don't care about a frame box around the camera view, then you can apply display:none or background: transparent to <ion-content> - but if you need/want a frame box then you must apply the display/background changes to a main content wrapper div inside the ion-content.

<body>
   <ion-nav-bar>
   <ion-nav-view id="appNavView"> // custom ID assigned
      <div class="pane" nav-view"active" ...>    // 1st element that needs transparency - can't assign ID
         <ion-tabs ...>
            <ion-nav-view name="tab-scanner"  ...>
               <ion-view id="ionViewScanner" class='pane' ...>  // 2nd element that needs transparency - custom ID assigned
                  <ion-content id="ionContentScanner" ...> // '3rd-A' element that needs transparency - custom ID assigned,  Use this if you don't care for a frame box
                     <div class="scroll" ....>  // auto created by Ionic - can't assign ID
                        <div id="pageWrapper"> // '3rd-B' element needs transparency/display:none if frame box wanted
                           <button id="scanOpen" ng-click="scanOpen();" ...>
                           ...ALL MY TAB-PAGE CONTENT .... 
                        </div>
                        <div id="scannerWrapper" style="display:none;background:transparent;height:100%;">  // the scanner frame box needed for 3-B
                            <div id="scannerTop" style="height:25%;background:white;">
                                <button id="scanStart" ng-click="scanStart()" ...>
                                <button id="scanCancel" ng-click="scanCancel();" ...>
                             </div>
                             <div id="scannerBox" style="height:50%;">
                                <div id="scannerLine" style="height:50%;border-bottom:1px solid red;"></div>
                              </div>
                              <div id="scannerBottom" style="height:25%;background:white;"></div>
                           </div>
                        </div> // end ionic created DIV
                     </ion-content>

And then in my controller I have:

  var appNavView = document.getElementById("appNavView") ;  
  var divPane = appNavView.children[0] ; 
  var pageWrapper = document.getElementById("pageWrapper") ;
  var scannerWrapper = document.getElementById("scannerWrapper") ;
  var scannerParent = scannerWrapper.parentNode ;

  function scannerBox(x) {
    if (x == 0) { // close
      divPane.style.background = "white" ;
      pageWrapper.style.display = "" ;
      scannerWrapper.style.display = "none" ;
      scannerParent.style.height = "" ;
    } else if (x == 1) { //open
      divPane.style.background = "none transparent" ;
      pageWrapper.style.display = "none" ;
      scannerWrapper.style.display = "" ;
      scannerParent.style.height = "100%" ;    
    }
  }

/// I cut all the prepare/getStatus stuff out - that all remains the same

  $scope.scanOpen = function() {
    scannerBox(1) ;
    QRScanner.show();
  }

  $scope.scanCancel = function() {
    QRScanner.cancelScan(function(status){
      $scope.scannerHide() ;
    });    
  }

  $scope.scannerHide = function() {
    scannerBox(0) ;   
    QRScanner.hide(function(status){
      console.log(status);
    });    
  }

  $scope.scannerDestroy = function() {
    scannerBox(0) ;       
    QRScanner.destroy(function(status) {
      console.log("Camera: destroyed") ;
    }) ;
  }

  //And then hide/destroy scanner when leaving TAB
  $scope.$on('$destroy', function() {
    $scope.scannerHide() ;
    $scope.scannerDestroy() ; 
  });

  $scope.$on("$ionicView.leave", function(event,data) {
    $scope.scannerHide() ;
    $scope.scannerDestroy() ; 
  }) ;