ionic media plugin - pass onStatusUpdate to mediaObject? - ionic2

I'm trying to use ionic native's media plugin like this:
record(){
...
return this.media.create(src,onStatusUpdate).then((mediaObj) => {
mediaObj.startRecord();
return mediaObj;
});
}
And I use the mediaObj returned from it elsewhere, but I also need to know the status of the mediaObj; this apparently comes from passing a second argument, a callback function, to the media.create() function. However, I don't know how to get the mediaObj's status in there. I know the following would work for just telling me the status, but I actually need to access it.
const onStatusUpdate = (status) => console.log(status);
So, the question is, is there a way to simply access the mediaObj's status?

The MediaPlugin status update notification is all you get so set a class property with the value you get when the status change.
To manage the MediaObject I set a property to the value obtained when the promise is resolved.
import { ApplicationRef } from '#angular/core';
...
...
export class PlayerPage {
track:any;
file:MediaObject = undefined;
position:any = undefined;
status:any = 0;
constructor(public ref ApplicationRef, public navCtrl: NavController, private navParams: NavParams, public AppstateProvider: Appstate, private media: MediaPlugin) {
this.track = navParams.get('track');
media.create('http://.../...mp3',(status)=>{
this.status = status;
this.ref.tick();
}).then((file: MediaObject) => {
this.file = file;
});
}
play() {
this.file.play();
}
The this.ref.tick(); is necesarry because Angular does not detect this property update - I tried publishing and subscribing Angular still did not detect the property update.

Related

Dart Testing with Riverpod StateNotifierProvider and AsyncValue as state

This is my first app with Dart/Flutter/Riverpod, so any advice or comment about the code is welcome.
I'm using Hive as embedded db so the initial value for the provider's state is loaded asynchronously and using an AsyncValue of riverpod to wrapped it.
The following code works but I've got some doubts about the testing approach, so I would like to confirm if I'm using the Riverpod lib as It supposed to be used.
This is my provider with its deps (Preferences is a HiveObject to store app general config data):
final hiveProvider = FutureProvider<HiveInterface>((ref) async {
return await App.setUp();
});
final prefBoxProvider = FutureProvider<Box<Preferences>>((ref) async {
final HiveInterface hive = await ref.read(hiveProvider.future);
return hive.openBox<Preferences>("preferences");
});
class PreferencesNotifier extends StateNotifier<AsyncValue<Preferences>> {
late Box<Preferences> prefBox;
PreferencesNotifier(Future<Box<Preferences>> prefBoxFuture): super(const AsyncValue.loading()) {
prefBoxFuture.then((value) {
prefBox = value;
_loadCurrentPreferences();
});
}
void _loadCurrentPreferences() {
Preferences pref = prefBox.get(0) ?? Preferences();
state = AsyncValue.data(pref);
}
Future<void> save(Preferences prefs) async {
await prefBox.put(0, prefs);
state = AsyncValue.data(prefs);
}
Preferences? get preferences {
return state.when(data: (value) => value,
error: (_, __) => null,
loading: () => null);
}
}
final preferencesProvider = StateNotifierProvider<PreferencesNotifier, AsyncValue<Preferences>>((ref) {
return PreferencesNotifier(ref.read(prefBoxProvider.future));
});
And the following is the test case, I'm mocking the Hive box provider (prefBoxProvider):
class Listener extends Mock {
void call(dynamic previous, dynamic value);
}
Future<Box<Preferences>> prefBoxTesting() async {
final hive = await App.setUp();
Box<Preferences> box = await hive.openBox<Preferences>("testing_preferences");
await box.clear();
return box;
}
void main() {
test('Preferences value changes', () async {
final container = ProviderContainer(overrides: [
prefBoxProvider.overrideWithValue(AsyncValue.data(await prefBoxTesting()))
],);
addTearDown(() {
container.dispose();
Hive.deleteBoxFromDisk("testing_preferences");
});
final listener = Listener();
container.listen<AsyncValue<Preferences>>(
preferencesProvider,
listener,
fireImmediately: true,
);
verify(listener(null, const TypeMatcher<AsyncLoading>())).called(1);
verifyNoMoreInteractions(listener);
// Next line waits until we have a value for preferences attribute
await container.read(preferencesProvider.notifier).stream.first;
verify(listener(const TypeMatcher<AsyncLoading>(), const TypeMatcher<AsyncData>())).called(1);
Preferences preferences = Preferences.from(container.read(preferencesProvider.notifier).preferences!);
preferences.currentListName = 'Lista1';
await container.read(preferencesProvider.notifier).save(preferences);
verify(listener(const TypeMatcher<AsyncData>(), const TypeMatcher<AsyncData>())).called(1);
verifyNoMoreInteractions(listener);
final name = container.read(preferencesProvider.notifier).preferences!.currentListName;
expect(name, equals('Lista1'));
});
}
I've used as reference the official docs about testing Riverpod and the GitHub issue related with AsyncValues
Well, I found some problems to verify that the listener is called with the proper values, I used the TypeMatcher just to verify that the state instance has got the proper type and I check ("manually") the value of the wrapped object's attribute if It's the expected one. Is there a better way to achieve this ?
Finally, I didn't find too many examples with StateNotifier and AsyncValue as state type, Is there a better approach to implement providers that are initialized with deferred data ?
I didn't like too much my original approach so I created my own Matcher to compare wrapped values in AsyncValue instances:
class IsWrappedValueEquals extends Matcher {
final dynamic value;
IsWrappedValueEquals(this.value);
#override
bool matches(covariant AsyncValue actual, Map<dynamic, dynamic> matchState) =>
equals(actual.value).matches(value, matchState);
#override
Description describe(Description description) => description.add('Is wrapped value equals');
}
In the test, the final part is a bit different:
Preferences preferences = Preferences.from(container.read(preferencesProvider.notifier).preferences!);
preferences.currentListName = 'Lista1';
await container.read(preferencesProvider.notifier).save(preferences);
// the following line is the new one
verify(listener(IsWrappedValueEquals(Preferences()), IsWrappedValueEquals(preferences))).called(1);
verifyNoMoreInteractions(listener);
}
I prefer my custom Matcher to the original code, but I feel that there are too many custom code to test something, apparently, common.
If anyone can tell me a better solution for this case, It'd be great.

AdonisJS 'bouncer' package not working as intended

As described here, I have implemented the authorization:
start/bouncer.ts:
import Bouncer from '#ioc:Adonis/Addons/Bouncer'
export const { actions } = Bouncer
export const { policies } = Bouncer.registerPolicies({
UserPolicy: () => import('App/Policies/UserPolicy'),
})
app/Policies/UserPolicy.ts:
import { BasePolicy } from '#ioc:Adonis/Addons/Bouncer'
import User from 'App/Models/User'
export default class UserPolicy extends BasePolicy {
public async before(user?: User) {
return user?.isSuperUser
}
public async list(user: User) {
await user.load('policies')
return user.policies.some((policy) => policy.identifier === 'user:list')
}
// ...
}
resources/vires/layouts/main.edge
#can('UserPolicy.list')
<p>Can see users list</p>
#endcan
And I cannot see the paragraph. In fact, I placed console.log inside the action, but it didn't get executed. I don't know if I'm missing anything. Can anyone shed some lights onto it?
Gotcha! This says:
The actual action callback is never executed when a before hook returns a true or a false value.
Make sure to return undefined if you want the bouncer to execute the next hook or the action callback.
These 2 statements were missed out. :)

web3.js how to search all the contracts ever created by and address

I am new to web3.js and solidity. My question is related to the way we search on the block-chain. Its easy to search for a particular contract if we know the contract address. However, how can we find and identify a specific type of contract using the from address used to create the contracts in the first place.
For eg.
I have a contract ContractA which is created by 'from' address AddressA using web3.js. Now I want to find all the instances of ContractA created by AddressA.
I tried searching using web3.eth.filter API but noting ever returns. Please help.
I also read about using registry pattern to store all the contracts and ask the registry, but couldn't find any useful example.
For those who are looking for a way, as Adam said in his post, there is no direct way to find contracts created by wallet address. Hence, we have to implement registry pattern as shown below to keep track of things and just ask that contract in web3.js, also shown below....
This is how my contract look like
contract ContractA {
bool public is_approved;
address public visa_details;
uint public artifact_count;
// constructors
function ContractA() public {
owner = msg.sender;
}
}
Here is the registry pattern contract
contract ContractARegistry {
mapping(address => address[]) user_contracts;
function registerContract(address contractA) public {
user_applications[msg.sender].push(contractA) - 1; // -1 is very important
}
function findContract(address user) view public returns (address[]){
return user_contracts[user];
}
}
In web3.js you may search like this (I am using Angular4)
import * as ContractA from '../../../../build/contracts/ContractA.json';
import * as UserContracts from '../../../../build/contracts/UserContracts.json';
import * as TruffleContract from 'truffle-contract';
import {Observable} from "rxjs/Observable";
declare var window: any;
#Injectable()
export class AppWeb3ContractAService {
CONTRACT_A = TruffleContract(ContractA);
USER_CONTRACTS = TruffleContract(UserContracts);
constructor(private appWeb3Svc: AppWeb3Service) {
console.log("Injecting the provider");
this.CONTRACT_A.setProvider(this.appWeb3Svc.currentProvider());
this.USER_CONTRACTS.setProvider(this.appWeb3Svc.currentProvider());
}
create(ethAddress): Observable<any> {
return Observable.create(observer => {
this.CONTRACT_A
.new({
from: ethAddress
})
.then(application => {
this.USER_CONTRACTS
.deployed()
.then(registry => {
registry.registerContractA(application.address, {from: ethAddress})
.then(result => observer.next(application))
.catch(error => observer.error(error));
})
.catch(error => observer.error(error));
})
.catch(error => observer.error(error));
});
}
findAll(ethAddress: string):
Observable<any[]> {
return Observable.create(observer => {
this.USER_CONTRACTS
.deployed()
.then(registry => {
registry.findUserContracts(ethAddress, {from: ethAddress})
.then(addresses => {
addresses.forEach(address => observer.next(this.CONTRACT_A.at(address)));
})
.catch(error => observer.error(error));
})
.catch(error => observer.error(error));
});
}
}
This is how my appWeb3Svc looks like
import {Injectable} from '#angular/core';
import {environment} from '../../../environments/environment';
import * as Web3 from 'web3';
declare var window: any;
#Injectable()
export class AppWeb3Service {
public web3: Web3;
checkAndInstantiateWeb3 = () => {
// Checking if Web3 has been injected by the browser (Mist/MetaMask)
if (typeof window.web3 !== 'undefined') {
console.warn(
'Using web3 detected from external source. If you find that your accounts don\'t appear or you have 0 MetaCoin, ensure you\'ve configured that source properly. If using MetaMask, see the following link. Feel free to delete this warning. :) http://truffleframework.com/tutorials/truffle-and-metamask'
);
// Use Mist/MetaMask's provider
this.web3 = new Web3(window.web3.currentProvider);
} else {
console.warn(
'No web3 detected. Falling back to ${environment.HttpProvider}. You should remove this fallback when you deploy live, as it\'s inherently insecure. Consider switching to Metamask for development. More info here: http://truffleframework.com/tutorials/truffle-and-metamask'
);
// fallback - use your fallback strategy (local node / hosted node + in-dapp id mgmt / fail)
this.web3 = new Web3(
new Web3.providers.HttpProvider(environment.HttpProvider)
);
}
};
constructor() {
this.checkAndInstantiateWeb3();
}
currentProvider() {
return this.web3.currentProvider;
}
eth() {
return this.web3.eth;
}
isAddress(ethAddress: string): boolean {
if (this.web3) {
return this.web3.isAddress(ethAddress);
}
return false
}
}
Hope this helps!
Unfortunately, there's no easy way to do this exact thing. web3.eth.filter can be used to apply filters on contract address, or they can be used to search across transaction logs (events emitted by a contract) where the sender is in the topic list.
If you want all transactions submitted by a specific address, you pretty much have to traverse each block on the chain and examine each transaction within each block to see if from is set to the address you're interested in.
// while looping through the block numbers you're interested in
web3.eth.getBlock(blockNum, (err, block) => {
if (block != null) {
block.transactions.forEach(tx => {
if (tx.from === myAddress) {
// Do something
}
}
}
});

paho mqtt javascript client cannot subscribe to a topic

AMQJS0005E Internal error. Error Message: Cannot read property 'subscribe' of undefined
I included eclipse paho javascript client library in my app.
connection is established but, I cannot subscribe to a topic.
here is the code that I used..
import { Component } from '#angular/core';
import { NavController, NavParams ,MenuController } from 'ionic-angular';
import { Setuser } from '../../providers/setuser';
import { Platform } from 'ionic-angular';
import { Paho} from 'ng2-mqtt/mqttws31';
/*
Generated class for the Usershome page.
See http://ionicframework.com/docs/v2/components/#navigation for more info on
Ionic pages and navigation.
*/
#Component({
selector: 'page-usershome',
templateUrl: 'usershome.html'
})
export class UsershomePage {
client :any;
message :any;
constructor(public navCtrl: NavController, public navParams: NavParams,public menu:MenuController,public setUserProvider: Setuser,public platform:Platform) {
this.menu.open();
}
ionViewDidLoad() {
this.menu.enable(true);
console.log('ionViewDidLoad UsershomePage');
}
exitApp(){
console.log("----------");
this.platform.exitApp();
}
connectToMqtt(){
this.client = new Paho.MQTT.Client("test.mosquitto.org",8080,"abc");
// set callback handlers
this.client.onConnectionLost = this.onConnectionLost;
this.client.onMessageArrived = this.onMessageArrived;
// connect the client
this.client.connect({onSuccess:this.onConnect});
}
// called when the client connects
onConnect() {
// Once a connection has been made, make a subscription and send a message.
console.log("onConnect");
this.client.subscribe("mitsuruog");
this.message = new Paho.MQTT.Message("Hello");
this.message.destinationName = "World";
this.client.send(this.message);
}
// called when the client loses its connection
onConnectionLost(responseObject) {
if (responseObject.errorCode !== 0) {
console.log("onConnectionLost:"+responseObject.errorMessage);
}
}
// called when a message arrives
onMessageArrived(message) {
console.log("onMessageArrived:"+message.payloadString);
}
}
Your immediate problem is solvable by modifying the line
this.client.connect({onSuccess:this.onConnect.bind(this)});
or, surprisingly for you, by removing all this. in front of client and message references.
You should learn what exactly means this in JavaScript. Not the same thing as in Java or C#. To understand why the removal works, learn about closures and arrow functions.
Good starting point (your question could be actually flagged as duplicate of this one):
How to access the correct `this` context inside a callback?

How to route after calling commit()

I am struggling a little with what to do after I call commit(). I want to determine how to route the user, depending on commit() being successful or if the server returns an error.
I read somewhere that if there is an error on the server then it can return a status code of >400 and errors as follows:
{ 'errors' : [ { 'errorCode' : [ 'duplicate-user' ] } ] }
On the client-side I have the following:
App.UsersController = Ember.ObjectController.extend({
createUser : function () {
'use strict';
var user = App.User.createRecord({
firstName : $("#firstName").val(),
lastName : $("#lastName").val(),
primaryEmailAddress : $("#primaryEmailAddress").val(),
password : $("#password").val()
}),
commitObserver = Ember.Object.extend({
removeObservers : function (sender) {
sender.removeObserver('isError', this, 'error');
sender.removeObserver('isValid', this, 'success');
},
error : function (sender, key, value) {
this.removeObservers(sender);
App.Router.router.transitionTo('duplicateuser');
},
success : function (sender, key, value) {
this.removeObservers(sender);
App.Router.router.transitionTo('usercreated');
}
});
user.get('transaction').commit();
user.addObserver('isError', commitObserver.create(), 'error');
user.addObserver('isValid', commitObserver.create(), 'success');
}
});
(Note: I am not using 'Ember.TextField' in my HTML hence the use of jQuery)
I have a few questions:
Is this the correct/best approach for handling commit()?
I've found I have to remove both observers as isValid is called after isError - is this to be expected?
How/can I access the server response as I want to be able to make a routing decision based on the error code?
The only way I can reference the router is through App.Router.router - is there a cleaner way?
If there is an error, do I need to do anything to remove the record from the store so it doesn't re-committed in the future?
From within a controller, you can do this:
this.get('target').transitionTo('another.route')
or, you can send an event to the current route and transition from there:
this.get('target').send('eventName');
or if you need to pass a model:
this.get('target').send('eventName', this.get('content'));
Simply use controller.transitionToRoute("your.route");
See this link for the source code...