Dart - Pass Interface as parameter - flutter

I'm looking for a similar solution for passing interface as paremeter in a function like Kotlin has:
test(object: Handler {
override fun onComplete() {
}
})
The only thing I find for Dart is using implements on the class, which is fine, but not what I need.
My approach so far has been making abstract class:
abstract class AuthListener{
void onChange(AuthState authState);
}
Triggering of listener:
isSignedInListener(AuthListener authListener){
FirebaseAuth.instance
.authStateChanges()
.listen((User user) {
if (user == null) {
return authListener.onChange(AuthState.SIGNED_OUT);
} else {
return authListener.onChange(AuthState.SIGNED_IN);
}
});
}
And now I need to listen for the response, which is where I need some help:

You can create a function and use it as a callback (pass to methods etc.).
Function can be placed into variable:
Function(AuthState authState) callback;
or as argument:
void isSignedInListener(Function(AuthState authState) callback) {}
auth.isSignedInListener((authState) {
// do something here
});

Related

How do I make a method that returns a stream<T> after modifying another stream<U>

I would like to make a helpfer method which takes a stream from a library (draw in this case) and changes the stream from Stream<UserContent> to Stream<Submission> and also filters the Submissions for duds.
So far I have this code but how do I return the stream now?
Stream<Submission> getSavedPosts({int limit = 20}) async* {
yield await _me!.saved(limit: limit).map((UserContent userContent) async {
try {
Submission sub = await _populateUserContent(userContent);
if (_filterPost(sub)) {
return sub;
}
} catch (err) {
print(err);
}
}); // The type 'Stream<Stream<Future<Submission?>>>' implied by the 'yield' expression must be assignable to 'Stream<Submission>'.
}
you should use asyncMap method on the stream rather than map.
Stream<ClassA> getOldStream() {}
Stream<ClassA> getNewStream() {
return getOldStream().asyncMap((event) async {
return event;
});
}
Note: yield and async* should be used in a generator function; mapping doesn't need a generator function

ReactiveX and Dart

I have a class Too
class Too{
bool isLogged = false;
BehaviorSubject suject = BehaviorSubject<bool>();
Too({required this.isLogged}){
suject = new BehaviorSubject<bool>.seeded(isLogged);
}
void login(){
isLogged = true;
suject.sink.add(isLogged);
}
void logOut(){
isLogged = false;
suject.sink.add(isLogged);
}
void dispose(){
suject.close();
}
and I also have the Foo class:
class Foo{
Too _too = new Too(isLogged: false);
_too.stream.listen((event) { print('${event}');});
}
My issue is When the user is calling the login() method of the Too class nothing happens at the level of the Foo class.
What I want to do is that if the user calls the login() method of the Too class and his isLogged attribute is set to true, then this change is done at the level of all the classes that have an attribute of the Too type.
Note: It's much easier to do it with Angular or Ionic using RxJS, but with dart, I don't know how to implement this mechanism.
Foo is not reacting because its listening to a different instance of Too.
The way you have it is that each new instance of Foo creates a new instance of Too. If I understand you correctly, you want all instances of Foo to react to any change to a single instance of Too.
You can use a singleton for this.
class Too {
// one of a few ways to make a singleton in Dart
Too._();
static final _instance = Too._();
factory Too() {
return _instance;
}
final subject = BehaviorSubject<bool>.seeded(isLogged);
static bool isLogged = false;
void login() {
isLogged = true;
subject.sink.add(isLogged);
}
void logOut() {
isLogged = false;
subject.sink.add(isLogged);
}
void dispose() {
subject.close();
}
}
Now you can have any Foo object listen to the same Too instance.
class Foo {
Foo() {
Too().subject.stream.listen((event) {
print('foo $event'); // this will now print whenever a subject from your Too class is updated.
});
}
}
Now for example you could test this by creating a button with this as the onPressed.
onPressed: () {
final foo = Foo(); // just created an example of a Foo object that will
// print the updated value of the Too singleton
Too().login();
},
RxDart is great. However when it comes to reactive programming in Flutter, I suggest checking out Get X as it simplifies a lot of stream based stuff.

Flutter, Dart. Create anonymous class

Maybe it's really dumb question. But I cannot believe there is no resources, where it's described. Even from the official documentation. What I'm trying to do, it's create Anonymous class for the next function.
How to create Anonymous class in Dart with custom function something like next in Kotlin?
Handler(Looper.getMainLooper()).post(Runnable() {
#override
open fun run() {
//...
}
private fun local() {
//....
}
})
Dart does not support creating an anonymous class.
What you're trying to do is not possible.
On the other hand, you can create anonymous functions. So you could use that to mimic an anonymous class.
The idea is to add a constructor of your abstract class, that defer its implementation to callbacks.
abstract class Event {
void run();
}
class _AnonymousEvent implements Event {
_AnonymousEvent({void run()}): _run = run;
final void Function() _run;
#override
void run() => _run();
}
Event createAnonymousEvent() {
return _AnonymousEvent(
run: () => print('run'),
);
}
It's not strictly the same as an anonymous class and is closer to the decorator pattern. But it should cover most use-cases.
This is an alternative way, but not fully equivalent:
Problem, e.g.:
I would like to implement OnChildClickListener inline in my code without class. For this method:
void setOnChildClickListener(OnChildClickListener listener) {
...
}
Instead of this:
abstract class OnChildClickListener {
bool onChildClick(int groupPosition, int childPosition);
}
use this:
typedef OnChildClickListener = Function(int groupPosition, int childPosition);
And in code you can implement it in this way:
listView.setOnChildClickListener((int groupPosition, int childPosition) {
// your code here
});
In other words do not use abstract class, but use typedef.

Play 2.5 preserve context in async calls

In our controller class we reach out to another service to get some data :
Future<JsonNode> futureSite = someClient.getSite(siteId, queryParams);
return FutureConverters.toJava(futureSite).thenApplyAsync((siteJson) -> {
Site site = Json.fromJson(siteJson, Site.class);
try {
return function.apply(site);
} catch (RequestException e) {
return e.result;
}
}).exceptionally(throwable -> {
if(throwable instanceof OurClientException) {
if(((OurClientException) throwable).httpStatusCode == 404) {
return entityNotFound("Site", siteId);
}
}
return null;
});
What we notice is that context which is set in unit tests (we use scalatest-play) is lost and becomes null after we make the Async call (FutureConverters.toJava(futureSite).thenApplyAsync((siteJson), as t is on a separate thread.
Which causes problem down in the controller code, where we use the above function ... request() would now throw a runtime exception saying there is no context available.
How can we preserve the context ?
You should inject play.libs.concurrent.HttpExecutionContext to your controller and then specify current context as second argument for CompletionStage#thenApplyAsync(..,..).
public class Application extends Controller {
#Inject HttpExecutionContext ec;
public CompletionStage<Result> index() {
someCompletableFuture.supplyAsync(() -> {
// do something with request()
}, ec.current());
}}
P.S. https://www.playframework.com/documentation/2.5.x/JavaAsync#Using-CompletionStage-inside-an-Action
I addition to Nick's V answer.
If you are building a non-blocking app using Play Java API, it might become quite cumbersome to inject HttpExecutionContext and pass ec.current()) every time you need to call methods on CompletionStage.
To make life easier you can use a decorator, which will preserve the context between calls.
public class ContextPreservingCompletionStage<T> implements CompletionStage<T> {
private HttpExecutionContext context;
private CompletionStage<T> delegate;
public ContextPreservingCompletionStage(CompletionStage<T> delegate,
HttpExecutionContext context) {
this.delegate = delegate;
this.context = context;
}
...
}
So you will need to pass context only once:
return new ContextPreservingCompletionStage<>(someCompletableFuture, context)
.thenCompose(something -> {...});
.thenApply(something -> {...});
Instead of
return someCompletableFuture.thenComposeAsync(something -> {...}, context.current())
.thenApplyAsync(something -> {...}, context.current());
That is particularly useful if you are building a multi-tier app, and passing CompletionStages between different classes.
Full decorator implementation example is here.

How do I mock Class<? extends List> myVar in Mockito?

I want to mock a Class in Mockito. It will then have a .newInstance() call issued which will be expected to return an actual class instance (and will return a mock in my case).
If it was setup correctly then I could do:
ArrayList myListMock = mock(ArrayList.class);
when(myVar.newInstance()).thenReturn(myListMock);
I know I can set it up so that a new instance of class ArrayList will be a mock (using PowerMockito whenNew), just wondering if there was a way to mock this kind of a class object so I don't have to override instance creation...
Below is the real class I'm trying to mock, I can't change the structure it is defined by the interface. What I'm looking for is a way to provide cvs when initialize is called.
public class InputConstraintValidator
implements ConstraintValidator<InputValidation, StringWrapper> {
Class<? extends SafeString> cvs;
public void initialize(InputValidation constraintAnnotation) {
cvs = constraintAnnotation.inputValidator();
}
public boolean isValid(StringWrapper value,
ConstraintValidatorContext context) {
SafeString instance;
try {
instance = cvs.newInstance();
} catch (InstantiationException e) {
return false;
} catch (IllegalAccessException e) {
return false;
}
}
Mockito is designed exclusively for mocking instances of objects. Under the hood, the mock method actually creates a proxy that receives calls to all non-final methods, and logs and stubs those calls as needed. There's no good way to use Mockito to replace a function on the Class object itself. This leaves you with a few options:
I don't have experience with PowerMock but it seems it's designed for mocking static methods.
In dependency-injection style, make your static factory method into a factory instance. Since it looks like you're not actually working with ArrayList, let's say your class is FooBar instead:
class FooBar {
static class Factory {
static FooBar instance;
FooBar getInstance() {
if (instance == null) {
instance = new FooBar();
}
return instance;
}
}
// ...
}
Now your class user can receive a new FooBar.Factory() parameter, which creates your real FooBar in singleton style (hopefully better and more threadsafe than my simple implementation), and you can use pure Mockito to mock the Factory. If this looks like it's a lot of boilerplate, it's because it is, but if you are thinking of switching to a DI solution like Guice you can cut down a lot of it.
Consider making a field or method package-private or protected and documenting that it's visible for testing purposes. Then you can insert a mocked instance in test code only.
public class InputConstraintValidator implements
ConstraintValidator<InputValidation, StringWrapper> {
Class<? extends SafeString> cvs;
public void initialize(InputValidation constraintAnnotation) {
cvs = constraintAnnotation.inputValidator();
}
public boolean isValid(StringWrapper value,
ConstraintValidatorContext context) {
SafeString instance;
try {
instance = getCvsInstance();
} catch (InstantiationException e) {
return false;
} catch (IllegalAccessException e) {
return false;
}
}
#VisibleForTesting protected getCvsInstance()
throws InstantiationException, IllegalAccessException {
return cvs.newInstance();
}
}
public class InputConstaintValidatorTest {
#Test public void testWithMockCvs() {
final SafeString cvs = mock(SafeString.class);
InputConstraintValidator validator = new InputConstraintValidator() {
#Override protected getCvsInstance() {
return cvs;
}
}
// test
}
}
I think you just need to introduce an additional mock for Class:
ArrayList<?> myListMock = mock(ArrayList.class);
Class<ArrayList> clazz = mock(Class.class);
when(clazz.newInstance()).thenReturn(myListMock);
Of course the trick is making sure your mocked clazz.newInstance() doesn't end up getting called all over the place because due to type-erasure you can't specify that it's actually a Class<ArrayList>.
Also, be careful defining your own mock for something as fundamental as ArrayList - generally I'd use a "real one" and populate it with mocks.