In my Angular 13 + Ionic 6 I have a camera with overlays page using:
import { CameraPreview, CameraPreviewOptions, CameraPreviewPictureOptions } from '@capacitor-community/camera-preview';
The page is working, and capturing images also works, only the camera view is not showing when run on Xiomu Rednote 8. On the screen. Instead, while the camera is OPEN, I see a black background on the screen, behind the visible overlays. It seems as if the camera preview is overwritten by an opaque black background, or something like that, although I do have:
ion-content {
--background: transparent !important;
}
So, the user experience is: a black screen with overlays buttons, fully functional, including the button capturing an image, and the image is actually captured OK and can be further processed/displayed.
The basic approach is from this guide: Creating a Custom Camera Preview Overlay with Ionic & Capacitor - YouTube
When run on Samsung Galaxy A32, this problem does not exist.
HOWEVER:
The Xiaomi Rednote 8 is always running my app in DARK THEME, regardless of my device settings (LIGHT / DARK) and even when I have these in my app.component:
document.body.setAttribute('data-theme', 'light');
document.body.classList.toggle('dark', false);
The Samsung Galaxy A32 is allways running my app in LIGHT THEME, regardless of my device settings (LIGHT / DARK).
So, the “hiding” camera preview may be associated with a DARK mode (which should not happen anyway - it should work in both modes), OR, it may be associated with the XIomi Rednote 8 (here, too, it should work anyway…).
I’m not sure how to proceed with this from here.
For completeness, here’s more code from the component:
home.page.html
<ion-content>
<div id="cameraPreview" class="cameraPreview">
<div *ngIf="cameraActive">
<ion-button [routerLink]="['/helpers']" id="helpers-icon" class="button-icon-top" fill="clear">
<div>
<ion-icon name="people-outline" slot="icon-only" size="large" class="buttons-icon"></ion-icon>
<label class="button-label">Helpers</label>
</div>
</ion-button>
<ion-button (click)="maintainMyInvitations()" id="my-invitations-icon" class="button-icon-top" *ngIf="isHelper" fill="clear">
<div>
<ion-icon name="receipt-outline" slot="icon-only" size="large" class="buttons-icon"></ion-icon>
<label class="button-label">My Invitations</label>
</div>
</ion-button>
<ion-button (click)="maintainSettings()" id="settings-icon" class="button-icon-top" fill="clear">
<div>
<ion-icon name="settings" slot="icon-only" size="large" class="buttons-icon"></ion-icon>
<label class="button-label">Settings</label>
</div>
</ion-button>
<ion-button (click)="captureImage()" id="capture-button" fill="clear">
<div>
<ion-icon name="radio-button-off" slot="icon-only" id="capture-icon"></ion-icon>
</div>
</ion-button>
<ion-button (click)="provideFeedback()" id="feedback-icon" class="button-icon-bottom" fill="clear">
<div>
<ion-icon name="document-text-outline" slot="icon-only" size="large" class="buttons-icon"></ion-icon>
<label class="button-label">Feedback</label>
</div>
</ion-button>
</div>
</div>
</div>
</ion-content>
home.page.scss
ion-content {
--background: transparent !important;
}
.button-label {
display: block;
font-size: 50%;
}
.button-icon-top {
width: 90px;
height: 90px;
margin-top: 10px;
.button-inner {
flex-flow: column;
.icon {
//margin-top: 10px;
font-size: 15em;
}
}
}
.button-icon-bottom {
position: absolute;
top: calc(100% - 5.5em);
height: 5em;
.button-inner {
flex-flow: column;
.icon {
//margin-bottom: 10px;
font-size: 1.5em;
}
}
}
.overlay {
position: absolute;
width: 100%;
height: 100%;
z-index: 10;
}
.cameraPreview {
display: flex;
position: absolute;
width: 100%;
height: 100%;
}
//If overlaying an image on top of the camera preview
.image-overlay {
z-index: 1;
position: absolute;
left: 25%;
top: 25%;
width: 50%;
}
#my-invitations-icon {
position: absolute;
//bottom: 30px;
left: calc(50% - 45px);
z-index: 11;
}
#helpers-icon {
position: absolute;
//bottom: 30px;
left: 10px;
z-index: 11;
}
#settings-icon {
position: absolute;
//bottom: 30px;
left: calc(100% - 100px);
z-index: 11;
}
#capture-button {
position: absolute;
//bottom: 30px;
left: calc(50% - 60px);
top: calc(100% - 220px);
width: 120px;
height: 120px;
z-index: 11;
.button-inner {
flex-flow: column;
}
}
#capture-icon {
font-size: 10em;
font-weight: bold;
}
.buttons-icon {
font-size: 14em;
margin-bottom: 5px;
}
#repeat-button {
width: 50px;
height: 50px;
left: calc(50% - 25px);
margin-top: 10px;
margin-bottom: 10px;
}
#repeat-icon {
font-size: 10em;
}
#get-help-button {
margin-top: 20px;
width: 200px;
left: calc(50% - 100px);
height: 60px;
}
home.page.ts (abbreviated)
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
//import { Plugins } from '@capacitor/core';
import { environment } from '../../environments/environment';
import { get, set, remove } from '../services/storage.service';
import { AwsFileUploadService } from '../services/aws-file-upload.service'
import { CameraPreview, CameraPreviewPlugin, CameraPreviewOptions, CameraPreviewPictureOptions, CameraPosition } from '@capacitor-community/camera-preview';
import { TigergraphService } from '../services/tigergraph.service';
import { Dialogs, DialogType } from '../Utilities/dialogs';
import { Services } from '../Utilities/general-service';
@Component({
selector: 'app-home',
templateUrl: 'home.page.html',
styleUrls: ['home.page.scss'],
})
export class HomePage implements OnInit {
image = null; //Base64 to save
imagePreview = null; //For displaying on screen
cameraActive = false;
chatText: string = '';
person: {};
learner: {};
isHelper = false;
helpersExists: boolean = false;
constructor(public tgdb: TigergraphService, private dialogs: Dialogs, private services: Services, private router: Router, private aws: AwsFileUploadService) {}
ngOnInit() {
this.dialogs.closeLoader();
this.openCamera();
// BUNCH OF DB STUFF COMES HERE
}
openCamera() {
this.imagePreview = null;
this.image = null;
const cameraPreviewOptions: CameraPreviewOptions = {
position: 'rear',
toBack: true,
disableAudio: true,
lockAndroidOrientation: true,
enableZoom: true,
parent: "cameraPreview",
className: "cameraPreview"
};
CameraPreview.start(cameraPreviewOptions);
this.cameraActive = true;
}
async stopCamera() {
console.log('Stopping Camera');
await CameraPreview.stop();
this.cameraActive = false;
}
async captureImage() {
const CameraPreviewPictureOptions: CameraPreviewPictureOptions = {
quality: 50
}
const result = await CameraPreview.capture(CameraPreviewPictureOptions)
this.imagePreview = 'data:image/jpeg;base64,' + result.value;
this.image = result.value;
this.stopCamera();
}
}
What am I missing?
(I tried posting this to StackOverflow 5 days ago - not even a comment from anyone.
I sure hope I can get a hint here from someone )
Thank you!