How to access device folder using react native file system - react-native

I needed to fetch files from a custom folder I created with my rncamera roll app, I used react-native-fs to access the folder but was not able to get the files even though I correctly specified the folder name, but I get a Possible Unhandled Promise Rejection (id:7): Error: Folder does not exist. How can I access this folder?
Even when I removed the folder name RNFS.readDir(RNFS.ExternalStorageDirectoryPath) to check my console.log result I got the error "isFile is not a function".
What is wrong with this code and how do I correct them.
UNSAFE_componentWillMount() {
RNFS.readDir(RNFS.ExternalStorageDirectoryPath+"myApp Videos")
.then((result) => {
console.log('GOT RESULT', result);
return Promise.all([RNFS.stat(result[0].path), result[0].path]);
})
.then((statResult) => {
let videos = []
var allowedExtensions = /(\.avi|\.mp4|\.mov|\.wmv|\.avi)$/i;
statResult.forEach(item => {
if (item.isFile() && !allowedExtensions.exec(item.originalFilepath)) {
videos.push(item)
}
});
console.log(videos)
})
}
setIndex = (index) => {
if (index === this.state.index) {
index = null
}
this.setState({ index })
}
render() {
return (
<View style={styles.container}>
<ScrollView
contentContainerStyle = {styles.scrollview}
{
...this.state.videos && this.state.videos.length > 0 && this.state.videos.map((p, i) => {
const isSelected = i === this.state.index;
const divide = isSelected && this.share === true ? 1 : 3;
return(
<Video
source={{uri: videos}}
style={{opacity: i === this.state.index ? 0.5 : 1, width: width/divide, height: width/divide}}
key={i}
underlayColor='transparent'
onPress={() => this.setIndex(i)}
ref={ref => {
this.player = ref;
}} // Store reference
onError={this.videoError} // Callback when video cannot be loaded
/>
)
})
}
>
</ScrollView>
</View>
);
}

Related

How to maintain a BLE device list while Scanning with react-native-ble-plx?

I'm trying to only print a list of bluetooth devices with their RSSI level.
But if I use some React setState() function inside the listener of the react-native-ble-plx startDeviceScan() I'm facing a warning Excessive number of pending callbacks 501 ...
const [devices, setDevices] = useState([]);
const startScan = () => {
manager.startDeviceScan(null, null, (error, device) => {
// Handling error
if (error) {
console.error('Error when scanning : ', error);
if (error.errorCode === BleErrorCode.LocationServicesDisabled) {
console.log('Please activate localisation');
}
if (error.errorCode === BleErrorCode.BluetoothUnauthorized) {
console.log('Permission are missing... BLE and/or Localisation ?');
}
return;
}
const index = devices.findIndex((d) => d?.id === device?.id);
if (index === -1) {
// Adding device in the list
setDevices((old) => [...old, device]);
} else {
// Update device informations
const old = [...devices];
old.splice(index, 1, device);
setDevices(old);
}
});
};
return (
<ScrollView persistentScrollbar>
<View>
{devices.map((d, i) => (
<Button
key={i}
onPress={() => connectTo(d)}
>
{d?.id} - {d?.localName || d?.name || '???'} - {d?.rssi}
</Button>
))}
</View>
</ScrollView>
)
How am I supposed to keep a list up to date ? ("Reactly" correct)

Trying to add a '[RCTVirtualText 507]' to a '[RCTView 509]')?

I had been developing my app for Web, and it has been working properly. However, when I ran the same app within Expo / Android, I got this error. Hard to know what it is about from the description.
This is the full error message:
Cannot add a child that doesn't have a YogaNode to a parent without a measure function! (Trying to add a '[RCTVirtualText 507]' to a '[RCTView 509]')
Do you know what it could possibly be?
This seems to be the js file that is triggering it:
...
export class SubjectListAssignScreen extends React.Component {
state = {
subjectList: [],
subListLoading: true,
};
constructor(props) {
super(props);
};
scrollDimensions = [{
width: Math.round(Dimensions.get('window').width - 20),
maxHeight: Math.round(Dimensions.get('window').height - 200)
}];
...
_getSubjects = async(text) => {
try {
await this.setState({ subListLoading: true });
let lQueryRes = await API.graphql(graphqlOperation(cqueries.listSubjectsCustom, {}));
await console.log('==> Subjects Query');
await console.log(lQueryRes);
await this.setState({ subjectList: lQueryRes.data.listSubjects.items });
await this.setState({ subListLoading: false });
}
catch (e) {
console.log("==> DB Error");
console.log(e);
await this.setState({ subListLoading: false });
};
};
...
_subjectItems = (value) => {
console.log(value.desc);
let lnum = (typeof value["num"] !== 'undefined') ? value["num"].toString() : null;
let desc = value["desc"].toString();
let lastName = (typeof value["users"][0] !== 'undefined') ? value["users"][0]["lastname"].toString() : null;
let ltype = value["type"].toString();
return (
<DataTable.Row onPress={() => {
this.props.navigation.navigate("UserListScreen", {pnum: lnum, ptype: ltype});
}}>
<DataTable.Cell>
{this._getTypeIcon(ltype)}
</DataTable.Cell>
<DataTable.Cell>
<Text>{desc}</Text>
</DataTable.Cell>
<DataTable.Cell>
<Text>{ lastName }</Text>
</DataTable.Cell>
</DataTable.Row>
);
};
async componentDidMount() {
try {
await this._getSubjects();
}
catch (e) {
console.log("==> componentDidMount error");
console.log(e);
};
};
isCloseToBottom = ({ layoutMeasurement, contentOffset, contentSize }) => {
const paddingToBottom = 20;
return layoutMeasurement.height + contentOffset.y >=
contentSize.height - paddingToBottom;
};
fetchMore = () => {
};
render() {
let sDimensions = this.scrollDimensions;
return (
<View style={{flex:20, margin:4, flexDirection:"column", justifyContent:"flex-start"}}>
<Title style={{flex:1}}>Lista de Demandas</Title>
<SafeAreaView style={[{flex:19, }, sDimensions]}>
<ScrollView
contentContainerStyle={{}}
onScroll={({nativeEvent}) => {
if (this.isCloseToBottom(nativeEvent)) {
this.fetchMore();
}}}
>
<DataTable>
<DataTable.Header>
<DataTable.Title>Type</DataTable.Title>
<DataTable.Title>Subj</DataTable.Title>
<DataTable.Title>Resp.</DataTable.Title>
</DataTable.Header>
{ !this.state.subListLoading ?
<FlatList
data={this.state.subjectList}
renderItem={({item})=>this._subjectItems(item)}
keyExtractor={item => item.desc}
/>
:
<ActivityIndicator />
}
</DataTable>
</ScrollView>
</SafeAreaView>
</View>
)
}
}
Using Expo 37, React Native paper and AWS Amplify.
As I had such a hard time trying to find which components were not compatible, I simply dropped my full development environment, create a clean one and pulled the latest commit again, checking all components version by version and making sure all of them were at the -g version. The error has stopped after that.

how to read file from local storage?

I am uploading image to device's local storage (Android), task is doing with success , now
I am facing issues when I try to read the file from the local storage , it pops up errors
saying that :
invariation Violation object are not valid React child
here is my code to upload the image :
let dirs = RNFetchBlob.fs.dirs;
RNFetchBlob.fs.exists(dirs.PictureDir + "/myfolder")
.then((exist) => {
//console.log(`file ${exist ? '' : 'not'} exists`);
if (!exist) {
try {
const fs = RNFetchBlob.fs;
/
RNFetchBlob.fs.mkdir(dirs.PictureDir + "/myfolder")
.then(() => {
let base64Str = data;
fs.writeFile(dirs.PictureDir + "/myfolder/" + imageName, base64Str, 'base64')
.then(() => {
RNFetchBlob.fs.scanFile([{
path: dirs.PictureDir + "/myfolder/",
mime: 'jpeg/jpg'
}]);
}).catch(() => {
alert("error");
})
here is the path to my image
const path =
dirs.PictureDir+"/myfolder/1718179779c718ba84098b90f6061816fba9f.jpg"
and here my code to access that image , could you please help
<ScrollView keyboardShouldPersistTaps="handled">
<View style={styles.containerWithMargin} >
{RNFetchBlob.fs.readFile(path, 'base64') .then( (data) =>
<Avatar
medium
onPress={this.onSelectPostImage.bind(this)}
source={{uri : data}}
/>
)}
</View>
RNFetchBlob.fs.readFile returns a promise, anything asynchronous should be in ComponentDidMount and from there you can use setState to set imageUrl for example, then in jsx you will have something like this
<View style={styles.containerWithMargin} >
{imageUrl &&
<Avatar
medium
onPress={this.onSelectPostImage.bind(this)}
source={{uri : imageUrl}}
/>
}
</View

react native mapbox dynamically added PointAnnotations are misplaced

I currently developing a react native app ( version 0.55.2) and mapbox/react-native (version 6.1.2-beta2)
I have a situation where some annotations are shown initially on map render, then further annotations are loaded when the user's zooms.
The first annotations are displayed at the right place.
However, when new annotations are added, there are all stuck at the top left corner.
Following their documentation, https://github.com/mapbox/react-native-mapbox-gl/blob/master/docs/MapView.md, I tried to call the function when the map is loaded or rendered. I even tried a setTimeout. The annotations always appears at the topleft map.
Any ideas how should I approach this?
THanks!
class map extends React.Component {
constructor(props) {
super(props);
this.getMapVisibleBounds = getMapVisibleBounds.bind(this);
this.state = {
...INIT_MAP_STATE
};
}
//compo lifecyle
componentDidUpdate(prevProps, prevState) {
if (this.state.userPosition.longitude !== prevState.userPosition.longitude) {
this.setBounds();//first annotations. works fine
}
if (this.state.zoomLevel !== prevState.zoomLevel) {
this.setBounds(); //update annotations. doesn't work
}
}
render()=>{
const { quest, checkpoint } = this.props;
const { selectedIndex } = this.state;
return (
<View style={styles.container}>
<Mapbox.MapView
styleURL={MAP_STYLE}
zoomLevel={this.state.zoomLevel}
centerCoordinate={[this.state.userPosition.longitude,
this.state.userPosition.latitude]}
style={styles.mapWrap}
>
{this.renderMap(checkpoint, "checkpoint")}
</Mapbox.MapView>
</View>
);
}
setBounds = () => {
this.getMapVisibleBounds(this.map)
.catch(err => {
console.error(err);
})
.then(bounds => {
this._setMapBounds(bounds);// set state bounds
return this.props.onLoadQuest(bounds); //api call
});
}
}
// annotations rendering
class checkPoint extends Component {
constructor(props) {
super(props);
}
renderAnnotations = (data, id) => {
const uniqKey = `checkpoint_${id}`;
return (
<Mapbox.PointAnnotation key={uniqKey} id={uniqKey} coordinate={[data[0], data[1]]}>
<TouchableWithoutFeedback onPress={idx => this.onSelect(id)}>
<Image source={checkPointImg} style={styles.selfAvatar} resizeMode="contain" />
</TouchableWithoutFeedback>
</Mapbox.PointAnnotation>
);
};
render() {
if (!this.props.checkpoint || isEmpty(this.props.checkpoint)) {
return null;
}
const { hits } = this.props.checkpoint;
if (!Array.isArray(hits)) {
return [];
}
return hits.map((c, idx) =>
this.renderAnnotations(c._source.location.coordinates, c._source.id)
);
}
}
"PointAnnotation" is legacy, try passing your points to as an object. You're map render will be so much faster once you make the swap. Something like this.
<MapboxGL.MapView
centerCoordinate={[ userLocation.longitude, userLocation.latitude ]}
pitchEnabled={false}
rotateEnabled={false}
style={{ flex: 1 }}
showUserLocation={true}
styleURL={'your_style_url'}
userTrackingMode={MapboxGL.UserTrackingModes.MGLUserTrackingModeFollow}
zoomLevel={10}
>
<MapboxGL.ShapeSource
key='icon'
id='icon'
onPress={this._onMarkerPress}
shape={{type: "FeatureCollection", features: featuresObject }}
type='geojson'
images={images}
>
<MapboxGL.SymbolLayer
id='icon'
style={layerStyles.icon}
/>
</MapboxGL.ShapeSource>
</MapboxGL.MapView>
Where "featuresObject" looks something like this...
let featuresObject = []
annotation.forEach((annot, index) => {
let lat = annot.latitude
let lng = annot.longitude
featuresObject[index] = {
type: "Feature",
geometry: {
type: "Point",
coordinates: [lng, lat]
},
properties: {
exampleProperty: propertyValue,
}
}
})
Example for polygon layer
Example with custom icon
You can add markers dynamically by using this code:
Create marker component:
const Marker = ({ coordinate, image, id }) => {
return (
<MapboxGL.MarkerView coordinate={coordinate} id={id}>
// Add any image or icon or view for marker
<Image
source={{ uri: image }}
style={{width: '100%', height: '100%'}}
resizeMode="contain"
/>
</MapboxGL.MarkerView>
);
};
Consume it inside MapBoxGL:
<MapboxGL.MapView
style={{
// it will help you keep markers inside mapview
overflow: 'hidden'
}}>
{markers &&
markers?.length > 0 &&
markers.map((marker, index) => (
<Marker
coordinate={[marker.longitude, marker.latitude]}
// id must be a string
id={`index + 1`}
image={getIconUrl(index)}
/>
))
}
</MapboxGL.MapView>
const layerStyles = Mapbox.StyleSheet.create({
icon: {
iconImage: "{icon}",
iconAllowOverlap: true,
iconSize: 0.5,
iconIgnorePlacement: true
}
});
const mapboxIcon = props => {
return (
<Mapbox.ShapeSource
shape={makeMapBoxGeoJson(props.datum, props.mapKey, props.name)}
key={`${props.name}_key_${props.mapKey}`}
id={`${props.name}_${props.mapKey}`}
images={getIcon(props.name)}
onPress={idx => (props.isActive ? props.onSelectId(props.mapKey) : null)}
>
<Mapbox.SymbolLayer
id={`${props.mapKey}_pointlayer`}
style={[layerStyles.icon, { iconSize: props.iconSize ? props.iconSize : 0.5 }]}
/>
</Mapbox.ShapeSource>
);
};

How to make react-native-banner-carousel load images from API(asynchronous)

I'm using https://github.com/f111fei/react-native-banner-carousel/
It works fined with hardcoded images path.
But this error happened if my images array is empty. It will show error as this image
I guess it caused by empty array (please correct me if im wrong). The state.carousels yet to loading to state when it render.
How can I make it asynchronous, so it can load the images dynamically.
So this is my code.
Dashboard.js
componentWillMount(){
this.props.carouselFetch();
}
renderPage(image, index) {
return (
<View key={index}>
<ImageFluid
source={{ uri: image }}
originalWidth={ 2500 }
originalHeight= { 1000 }
/>
</View>
);
}
render(){
const images = this.props.carousels;
return(
......
<Carousel
autoplay
autoplayTimeout={5000}
loop
index={0}
showsPageIndicator={ false }
pageSize={BannerWidth}
>
{ images.map((image, index) => this.renderPage(image, index))}
</Carousel>
......
);
}
const mapStateToProps = (state) => {
const carousels = state.carousel;
return { carousels };
};
CarouselActions.js
export const carouselFetch = () => {
return (dispatch) => {
fetch('API json')
.then((response) => response.json())
.then((response) => {
if (response.Status === 'Fail') {
return Promise.reject(response)
}
return response
})
.then(carousels => {
carouselFetchSuccess(dispatch, carousels);
})
.catch(() => console.log("Error"));
};
};
const carouselFetchSuccess = (dispatch, carousels) => {
dispatch({
type: CAROUSEL_FETCH_SUCCESS,
payload: _.map(carousels.data, i => i.image_path)
});
};
My Sample API json
The package required sample array method
render(){
const images = this.props.carousels;
if (!images || images.length === 0) {
return null;
}
return(
......
<Carousel
autoplay
autoplayTimeout={5000}
loop
index={0}
showsPageIndicator={ false }
pageSize={BannerWidth}
>
{ images.map((image, index) => this.renderPage(image, index))}
</Carousel>
......
);
}
Don't render carousel when the image list length is 0.
First use :
const images = ( this.props.carousels || [] ).map( (image) => ( {
value: carousels .name,
label: carousels .id,
order: carousels .data.
} );
You have a simple array of objects not an nested array, your response it's a simple res.data and not a res.carousel.data, if you use console.log(res) you will see your array, check that.