How to answer phone calls in React Native? - ecmascript-6

So I'm trying to programmatically answer phone calls (on Android 10) in React Native. I tried using react-native-callkeep but it seems that I can't figure out the documentation. Here's my code using the package:
// Listening on call state changes
this.listener = EventRegister.addEventListener(
CallManager.listenerName,
type => {
switch (type) {
case CallManager.eventNames.Incoming:
self.setState({
isCurrentlyBeingCalled: true,
});
CallKeep.answerIncomingCall(); // This won't work
break;
}
},
);
The documentation tells me to pass a uuid - but what uuid??? I tried using random uuids but that doesn't work either.
Does someone maybe know another better package to simply answer phone calls in React Native?

If you look towards the lower end of the documentation, you will see the "Events" section. There you can register listeners which'll give you the callUUID so you can pass it into your method.
import RNCallKeep from 'react-native-callkeep';
RNCallKeep.addEventListener('didReceiveStartCallAction', ({ handle, callUUID, name }) => {
console.log(`Received Start Call Event - Name: ${name}, Uuid: #{callUUID}`;
RNCallKeep.answerIncomingCall(callUUID);
});
I haven't tested this, just what i compiled from the documentation, but try it out.

Related

Composable functions in Puppeteers page.Evaluate

I'm relatively new to puppeteer and I'm trying to understand the patterns that can be used to build more complex apis with it. I am building a cli where I am running a WebGL app in puppeteer which i call various functions in, and with my current implementation i have to copy and paste a lot of setup code.
Usually, in every cli command i have to setup pupeteer, setup the app and get access to its api object, and then run an arbitrary command on that api, and get the data back in node.
It looks something like this.
const {page, browser} = await createBrowser() // Here i setup the browser and add some script tags.
let data;
page.exposeFunction('extractData', (data) => {
data = data;
})
await page.evaluate(async (input) => {
// Setup work
const requestEvent = new CustomEvent('requestAppApi', {
api: undefined;
})
window.dispatchEvent(requestEvent);
const api = requestEvent.detail.api;
// Then i call some arbitrary function, that will
always return some data that gets extracted by the exposed function.
const data = api.arbitraryFunction(input);
window.extractData(data)
}, input)
What i would like is to wrap all of the setup code in a function, so that i could call it and just specify what to do with the api object once i have it.
My initial idea was to have a function that will take a callback that has this api object as a parameter.
const { page, browser } = wait createBrowser();
page.exposeFunction(async (input) =>
setupApiObject(((api) =>
api.callSomeFunction(input)
), input)
However, this does not work. I understand that puppeteer requires any communication between the node context and the browser to be serialised as json, and obviously a function cant be. Whats tripping me up is that I'm not actually wanting to call these methods in the node context, just have a way to reuse them. The actual data transfer is already handled by page.exposeFunction.
How would a more experienced puppeteer dev accomplish this?
I'll answer my own question here, since i managed to figure out a way to do it. Basically, you can use page.evaluate to create a function on the window object that can later be reused.
So i did something like
await page.evaluate(() => {
window.useApiObject = function(callback: (api) => void){
// Perform setup code
callback()
}
})
Meaning that later on i could use that method in the browser context and avoid redoing the setup code.
page.evaluate(() => {
window.useApiObject((api) => {
api.someMethod()
})
})

ember hasDirtyAttributes do not work with object (json)

I have a model:
export default Model.extend({
title: attr('string'),
attributes: attr('jsonb')
});
Where attributes is a custom json filed stored as jsonb in Postgres.
let say:
{
"name":"Bob",
"city":""
}
So I can easily manipulate attributes using template
<form.element .. #property="attributes.city"/> or model.set('attributes.city','city name')
Problem: hasDirtyAttributes do not changing because technically we have old object. But when I try to copy object let say
JSON.parse(JSON.stringify(this.get('attributes')) hasDirtyAttributes works as expected
So how to write some Mixin for a Model or other workaround which on the change of any attribute property will mark hasDirtyAttributes as true. I will update whole object so doesn't matter which property actually was changed.
Same problem: https://discuss.emberjs.com/t/hasdirtyattributes-do-not-work-with-nested-attributes-json-api/15592
existing solution doesn't work for me at all:
ember-dirtier
ember-data-relationship-tracker
ember-data-model-fragments (a lot of changes under the hood and broke my app)
Update:
Some not perfect idea that help better describe what I'm want to achieve:
Let say we adding observer to any object fileds:
export default Model.extend({
init: function(){
this._super();
this.set('_attributes', Object.assign({}, this.get('attributes'))); //copy original
Object.keys(this.get('attributes')).forEach((item) => {
this.addObserver('attributes.'+ item, this, this.objectObserver);
});
}
...
})
And observer:
objectObserver: function(model, filed){
let privateFiled = '_' + filed;
if (model.get(privateFiled) != model.get(filed)) { //compare with last state
model.set(privateFiled, this.get(filed));
model.set('attributes', Object.assign({}, this.get('attributes')) );
}
}
It's works, but when I change one filed in object due to copying object objectObserver faired again on every filed. So in this key changing every filed in object I mark observed filed as dirty
The further ember development will reduce using of event listener and two-way binding, actually Glimmer components supports only One-way Data Flow. So to be friendly with future versions of emberusing one-way data flow is good approach in this case to. So In my case as I use ember boostrap solution looks like
<form.element #controlType="textarea" #onChange={{action 'attributeChange'}}
where attributeChange action do all works.
New Glimmer / Octane style based on modifier and looks like:
{{!-- templates/components/child.hbs --}}
<button type="button" {{on "click" (fn #onClick 'Hello, moon!')}}>
Change value
</button>

Using React Router and React.rb

I am trying to use React Router from within react.rb. I started using the reactor-router Gem, but the Gem only works with React Router < 1 and I am using React Router 2.4.0 and the API is quite different.
Over the last weeks I have taken a few approaches to getting this working but none of the approaches have been correct, each having their own fault.
Please will someone steer me in the right direction as I am all out of options.
In terms of setup, I am using Webpack to require React and React Router so the application.js which is injected by Webpack looks like this:
React = require('react')
ReactDOM = require('react-dom')
_reactRouter = require('react-router')
Approach 1 - create the Router as native JS and call ReactDOM.render to render the router when rendering a top level component
before_mount do
#admin_members = React::API::create_native_react_class(Components::Company::AdminMember)
#squad_index = React::API::create_native_react_class(Components::Squad::Index)
#squad_show = React::API::create_native_react_class(Components::Squad::Show)
#tribe_index = React::API::create_native_react_class(Components::Tribe::Index)
#tribe_show = React::API::create_native_react_class(Components::Tribe::Show)
end
and then rendering the router to a div in after_mount:
after_mount do
`ReactDOM.render(React.createElement(
_reactRouter.Router,
{ history: _reactRouter.browserHistory },
React.createElement(_reactRouter.Route, { path: "admin/members", component: #{#admin_members} }),
React.createElement(_reactRouter.Route, { path: "/squads", component: #{#squad_index} }),
React.createElement(_reactRouter.Route, { path: "/squads/:squad_id", component: #{#squad_show} }),
React.createElement(_reactRouter.Route, { path: "/tribes", component: #{#tribe_index} }),
React.createElement(_reactRouter.Route, { path: "/tribes/:tribe_id", component: #{#tribe_show} })
), document.getElementById('bh_router_div')
);`
end
This approach, although not pretty, seems to work in that the Router is created and functions as expected. A URL or /tribe/22 will load the correct TribeShow component and will pass the correct ID to the component.
The problem I have with this approach is when it comes to creating a Link as the Link component does not share the same context as the router. I believe this is down to ReactDOM.render being called once by react-rb and then once again in the code above. This creates two root components on the page (TopLevelRailsComponent) and (ReactRouter).
The Link is created thus:
class MyRouter < React::NativeLibrary
imports '_reactRouter'
end
And then used in a components render method like this:
MyRouter.Link({to: "/admin/members"}) { "and here is the link"}
The link is rendered, but clicking on it gives the following warning and does not navigate to the component:
Uncaught TypeError: Cannot read property 'push' of undefined
Looking at the properties of the Link Component I see that context is null and I believe this is why. It seems the Link is being being drawn outside the context of the router.
Approach 2 - use the react-rb API to render the router so that ReactDOM.render is not being called twice on the page
This seems to be a better approach but so far I have not managed to get this to work properly.
Building on how I create the Link above, in the render method of a component:
MyRouter.Router({history: `_reactRouter.browserHistory` },
MyRouter.Route({ path: "/admin/members", component: #admin_members})
) {}
But I get the following warning and the page does not render:
Uncaught Invariant Violation: <Route> elements are for router configuration only and should not be rendered
Approach 3 - build the Route component in native JS so that it does not get rendered:
`var AppRoutes = React.createElement(_reactRouter.Route, { path: "/admin/members", component: #{#admin_members} });`
MyRouter.Router({history: `_reactRouter.browserHistory` },
`AppRoutes`
) {}
This gets past the previous error, BUT the router does not actually route and I get the following warning (and the component does not render):
Warning: [react-router] Location "/admin/members" did not match any routes
history: As a side note, in both the examples above, I have tried to set history as such:
MyRouter.Router({history: MyRouter.browserHistroy },
`AppRoutes`
) {}
But I get a warning about providing a depreciated history and when I check the value it is null. Using _reactRouter.browserHistorygets past this warning. I am not sure if this is relevant to this fact that the router is not routing or not.
I would really appreciate any help or steer on this. Even a steer as to which of the approaches is the correct and and any hints as to how to proceed would be very welcome indeed.
This has been addressed in the V2.4.0 branch of reactrb-router https://github.com/reactrb/reactrb-router/tree/v2-4-0
Also please note the new DSL

Create Node with an integer as property with Neo4j REST API

I'm currently working a Neo4j REST API wrapper for nodejs (node-neo4j).
Just making it ready for v2.0 of Neo4j
My fork: https://github.com/Stofkn/node-neo4j of https://github.com/philippkueng/node-neo4j
Is it possible to use the REST API to create a node with an integer like:
{ name: 'Kristof', age: 77 }
It creates a Node like this { name: 'Kristof', age: '77' }
Is the only workaround a Cypher query or a server plugin?
It should create the node with an numeric property, if it doesn't it's a bug but the code for that has been around for a long while.
For 2.0 I'd suggest to focus on the transactional endpoint first and add support for the REST API later on :)
Thanks for your help Michael.
I had to remove the type 'form' otherwise the integer is interpreted as a string.
My solution for a simple node creation without labels:
var request = require('superagent');
request
.post(this.url + '/db/data/node')
.send(node)
// .type('form') remove this line
.set('Accept', 'application/json')
.end(function(result){
if(typeof result.body !== 'undefined')
that.addNodeId(result.body, callback);
else
callback(new Error('Response is empty'), null);
});

Backbone JS w/ Coffeescript basic GET

I'm learning both CoffeeScript and Backbone JS. I want to load just one piece of equipment. Yes, I know I don't need Backbone JS for this - But it helps me to learn if I start with basics. As soon as the page loads, I want it to grab some JSON from the server, and display it on the page.
Here is my coffeescript so far:
jQuery ->
class Equipment extends Backbone.Model
defaults:
title:''
desc:''
url:'/getData'
class ItemView extends Backbone.View
tagName: 'div'
initialize: ->
_.bindAll #, 'render'
render: ->
$(#el).html """
<h1>#{#model.get 'title'}</h2>
<p>#{#model.get 'desc'}</p>
"""
#
class AppRouter extends Backbone.Router.extend
routes:
'':'getData'
getData: ->
#equipment = new #Equipment()
#equipmentView = new #ItemView
model: #equipment
#equipment.fetch()
$('div').html #equipmentView.render().el
appRouter = new AppRouter
Backbone.history.start()
I feel like I have all the pieces in place, and am getting no errors (either in compilation or running the page).
The basic JSON I expect back from the server is just a PHP page echoing this:
{
"title": "title",
"desc": "description"
}
What am I missing?
Does #equipment.fetch() even trigger a HTTP request?
To my understanding you must set the id: #equipment = new #Equipment(id:123) which would trigger a "/getData/123" request.
or specify the url in the fetch: #equipment.fetch(url:"/getData") to load
But then the view would still be empty, because the data isn't yet loaded when the View render() is executed. Backbone doesn't automatically update views when models change (Like EmberJS does).
Add #listenTo(#model, "change", #render) to the initialize method to re-render when the model changes.
I found a nice guide/tutorial for you
http://adamjspooner.github.com/coffeescript-meet-backbonejs/
You have to tell Backbone to route your initial url ('') like this :
Backbone.history.start pushState: true
You also should pass an id (I think Backbone will request /getData/undefined in your case and on a side note I think you should use coffee's fat arrows instead of bindAll (it's one of the many great thing about coffeescript, but then you should get rid of some of the #s because they won't refer to window anymore...