Issue displaying multiple video instances in flatlist - ios

Im having some troubles displaying videos in a flatlist. It seems to be a specific iOS issue on real devices as it works fine in simulator and on android. Using react-native-video and in the error logs im getting AVFoundationErrorDomain with error code 11839. After searching a while it seems that the real devices have limits on how many video instances they can show at a time.
So I'm getting a black screen in the video component with greyed out controls with a crossed out play button. The structure is flatlist -> child -> Video. I’ve tried changing the order and moving the video component up a level but same issue. The flatlist will render items 10 at a time and can contain images or videos.
I’ve tried saving the key of the item that renders with onViewableItemsChanged prop and save it and a maximum of ten in redux.Then i fetch this array where the video component is rendered to only render the video component where the id of the item is same as in the array from redux. This should in theory only render items that are viewed or has been viewed recently.
Before this the videos wasn’t loaded at all now they are rendered for a while but after a couple has been rendered and played the issues is back. The actual component is alwayes rendered (if the keys/id has been saved and fetched to redux) but has a black screen
Anyone with another solution or input on my code to help me with this issues is greatly appreciated.
Reducer:
let feedIdsArr = [...state.savedFeedIds];
let newFeedId = action.payload;
if (feedIdsArr.length < 10) {
if (!feedIdsArr.includes(newFeedId)) {
feedIdsArr.push(newFeedId)
}
} else {
feedIdsArr.shift()
}
console.log("SAVE_FEED_ID", feedIdsArr);
return {...state, savedFeedIds: feedIdsArr};
Action:
return dispatch => {
dispatch({
type: SAVE_FEED_ID,
payload: id
});
}
}
Render:
if (this.props.savedFeedIds.includes(this.props.feed.feedItemId)) {
return (
<Video
source={{uri: url}}
style={this.calculateVideoAspectRatio(videoGallery, orientation)}
controls={true}
paused={true}
resizeMode={orientation === 'portrait' ? "cover" : null}
fullscreen={false}
ref={r => this.player = r}
onError={err => console.log("VIDEO ERROR", err)}
/>
)
}
onViewableItemsChanged:
onViewableItemsChanged = ({viewableItems}) => {
viewableItems.forEach(item => {
if (item.item.videoGallery) {
this.props.feedItemIds(item.key)
}
})
};

Related

navigator.mediaSession.metadata not updating after page reload

I am currently tying our audio player with mediaSession.
Everything is working as it should, when I hit play and update navigator.mediaSession.metadata, it's properly displayed in the notification on desktop and mobile.
But after I reload the page and hit play, the notification has always default values (website URL as a title and link rel="icon" for the artwork). This only happens after I reload the website. If I close it and open again the notification is working properly again.
Here's how it's done:
//...
initialConfiguration: {
title: 'Initial Title',
artist: 'Initial Artist',
album: '',
artwork: [
{ src: "initial/artwork/url.jpg", sizes: "512x512", type: "image/jpg" },
]
},
currentMetadata: null,
setMediaSessionMetaData: function(){
let self = this;
if ('mediaSession' in navigator) {
if( !self.currentMetadata ){
self.currentMetadata = new MediaMetadata(self.initialConfiguration);
}else{
// Update existing metadata
self.currentMetadata.title = "New Title";
self.currentMetadata.artist = "New Artist";
self.currentMetadata.artwork = [
{ src: "new/artwork/url.jpg", sizes: '512x512', type: "image/jpg" },
];
}
navigator.mediaSession.metadata = self.currentMetadata;
}
},
//...
This function works perfectly fine on first page load, when I hit play for the first time it loads the initialConfiguration and if I call the function again the title and artwork gets updated. But after reload, the notification has always default values ignoring my configuration.
Is there a bug in mediaSession, I didn't find anything regarding this issue on mediaSession github page (https://github.com/w3c/mediasession/issues) and searching this issue gives me zero results.
After Searching for days and not finding anything....
I discovered a workaround. It has to do with the performance.navigation.type when you first open a page it is set to 0 and after a refresh it gets set to 1. I was curious if this had any effect on the mediasession so I figured out how to "Hard Refresh" the page by using window.open(window.location.href, "_self");, because apparently that generates a "Hard Refresh". After that the mediasession works again. so what I did was setup an onload function that checks to see if performance.navigation.type == 1 and if so then do a "Hard Refresh"
window.onload = function() {
if (performance.navigation.type != 0) {
window.open(window.location.href, "_self");
}
};
Now when the user refresh's it will do a "Hard Refresh".
Also make sure to move the window. Onload line to the end of the javascript file or after the initial function

Style the default "No video source" / "No video permissions" black rectangle

When the user is prompted for a permission on Safari, the video element is shown as a black rectangle with a strikethrough play button. How do I change this element's styling? Does it have a specific ID / class / tag?
I'm using Quagga JS as a barcode scanner. AFAIK Quagga creates a video element, then asks for camera permission. The optimal result would be to hide the element using display:none;, but I can't think of any way to accomplish this. I need the element to display the camera feed once the scanner has its permission, but before that it should either paint the screen black or be hidden.
I've fixed it by hiding it via JavaScript and showing it once the Quagga Feedback has finished. Note that a pure CSS solution would be much prettier.
// Hide the preview before it's fully initialised.
$('#videoBoundingBox').hide();
Quagga.init({
inputStream: {
name: "Live",
type: "LiveStream",
target: document.querySelector('#videoBoundingBox')
},
decoder: {
readers: [
"code_128_reader",
"ean_reader"
]
}
}, function (err) {
if (err) {
console.log(err);
setResult(err);
err = err.toString();
if (err.search("NotFoundError")) {
// No camera found. The user is probably in an office environment.
// Redirect to previous orders or show a background image of sorts.
} else if (err.search("NotAllowedError")) {
// The user has blocked the permission request.
// We should ask them again just to be sure or redirect them.
} else {
// Some other error.
}
return;
}
// Hide the preview before it's fully initialised.
$('#videoBoundingBox').show();
setResult("Initialization finished. Ready to start");
console.log("Initialization finished. Ready to start");
Quagga.start();
initializeQuaggaFeedback();
});

How to take photo continuously using XLabs

Currently I'm developing a cross-platform app using Shared Library that able to take photos. I'm using XLabs.Forms V2.0.5782 package to do this app. I successfully developed this simple app but it only allows me to take one picture at a time.
I messed around with the codes and I managed to take multiple pictures but the problem is, the camera will be closed when I clicked 'Use Photo' and reopen again to take the next photo. What I wanted is, when I clicked 'Use Photo', the camera will reopen on the spot instead of closing and reopen.
Here's the code I did to take multiple pictures but I know it is not the right way to do it. It is in button clicked event.
IDevice device = Resolver.Resolve<IDevice>();
IMediaPicker media = device.MediaPicker;
//More codes here
async void TakePicture(object sender, System.EventArgs e)
{
var options = new CameraMediaStorageOptions()
{
PercentQuality = 50,
DefaultCamera = CameraDevice.Rear,
MaxPixelDimension = 250
};
var cancel = false;
while (!cancel)
{
await media.TakePhotoAsync(options).ContinueWith(t =>
{
if (t.IsFaulted) //If there's an error when taking photos
{
DisplayAlert("Error", "An error occurred when taking photo.\nPlease try again.", "OK");
}
else if (t.IsCanceled) //When the user click 'Cancel'
{
cancel = true;
}
else //When the user click 'Use Photo' - Here's the part where the camera will close and reopen until user click 'Cancel'
{
var img = ImageSource.FromStream(() => t.Result.Source);
picList.Add(img);
}
});
}
if (picList.Count > 0)
{
scrollParent.IsVisible = true;
imageScroll.Children.Clear();
foreach (var pl in picList)
{
var image = new Image()
{
Source = pl,
HeightRequest = 150,
HorizontalOptions = LayoutOptions.Start,
Aspect = Aspect.AspectFit,
Margin = new Thickness()
{
Right = 10
}
};
imageScroll.Children.Add(image);
}
}
}
Is it possible for me to take multiple pictures with XLabs.Forms and is there a proper way? I've search everywhere but found nothing about this. Any help will be much appreciated. Thanks!
Note:
I'm using Visual Studio for Mac Version Preview 9 (7.0 build 2943)
I've only tested on iPhone running iOS 10.2. Have not tested on Android device yet
Here's a gif showing an example of my app. I think this will make you guys have a better understanding of what I want and what is happening
Please note that 3 photos are taken in this example. The camera opens up four times. After taking each photo, I clicked 'Use Photo' on the bottom right and when the camera open on the 4th time, I clicked 'Cancel' on the bottom left to stop the loop
Thank you!

meteor cfs:filesystem upload from ios to server result in zero bytes file

I'm running on iOS using cordova capture and cfs filesystem.
after capturing video or images i'm using the upload.
no errors but, files are zero/0 size in the end.
(I'm working on my macbook pro by the way)
this is my collection and store declaration:
Videos = new FS.Collection("eventVideos", {
stores: [new FS.Store.FileSystem("eventVideos", {
path: "~/Documents/dev/chain/public/videoUploads"})]
});
this is the cordova capture code residing in a template event:
navigator.device.capture.captureImage(videoCaptureSuccess, videoCaptureError, {limit: 1});
i'll spare you the videoCaptureError function since it doesn't really do anything right now, but the videoCaptureSuccess looks like this:
videoCaptureSuccess = function(mediaFiles) {
var i, path, len;
for(i = 0, len = mediaFiles.length; i < len; i++) {
path = mediaFiles[i].fullPath;
Videos.insert(mediaFiles[i], function(err, fileObj) {
alert(fileObj.size());
if(err) {
console.log(err);
}
});
}
};
note that the alert inside videoCaptureSuccess returns a positive number meaning there is data in there, the pictures are also saved on the device.
what's wrong?
---update---
when i click the camera from the app this message shows in xcode console:
Snapshotting a view that has not been rendered results in an empty snapshot. Ensure your view has been rendered at least once before snapshotting or snapshot after screen updates.
worked it out eventually using the amazing support on Meteor forums.
the complete solution is here

webkitIsFullScreen on ipad/iphone?

I have an application that requires a page refresh whenever the orientation changes (ipad/iphone). Within this application, HTML5 videos also gets presented at certain times in UX. Whenever a user is viewing a video in full screen mode, their first inclination is to rotate the device to landscape orientation if it was not already in that mode. When they do this, however, it triggers the nasty page reload, effectively ending their viewing session. By tapping into webkit full screen API I was able to write logic to control this behavior, which works perfectly on Safari desktop as well as with the iPad/iPhone user agent selected in developer tools, but it DOES NOT work on the native iphone/ipad.
document.webkitIsFullScreen returns false/true correctly in console in Safari, but comes up as undefined on iphone/ipad. Can anyone tell me how to accomplish this on ipad/iphone, since these are the only devices that require this functionality anyway? Or is there a much simpler solution that I am overlooking? Any help is greatly appreciated!
$(document).ready( function () {
var video = document.getElementById('video');
var canrefresh = true;
video.addEventListener("webkitfullscreenchange",function(){
// Detects if video is in full screen mode and toggles canrefresh variable
// canrefresh = false when webkitfullscreenchange event is heard
// canrefresh = true after exiting full screen
if (canrefresh == true) {
canrefresh = false;
} else {
canrefresh = true;
}
console.log(document.webkitIsFullScreen+' | '+canrefresh);
}, false);
$(window).resize(function() {
// Look to make sure not in full screen, and canrefresh variable is true before refreshing page
if((document.webkitIsFullScreen == false) && (canrefresh == true)){
window.location = window.location.href+'?v='+Math.floor(Math.random()*1000);
}
});
console.log(document.webkitIsFullScreen+' | '+canrefresh);
$('body .test').text(document.webkitIsFullScreen+' | '+canrefresh); // document.webkitIsFullScreen is returning 'false' in Safari (correct), but 'undefined' on native iphone/ipad device
});
The equivalent property which is compatible with Mobile Safari is the webkitDisplayingFullscreen property on the HTMLVideoElement DOM object.

Resources