How to pass a parameter to a Mobx Controller (Flutter) - flutter

I am an Android Developer and new to Flutter. I really like the way Mobx works, because it remembers me Android's ViewModel. By the way, when I create a ViewModel, I like to create it passing the repository as a parameter, so I can test it with different Data Sources (ie. local or cloud).
So, this is my class right now.
import 'package:mobx/mobx.dart';
part 'create_bill_controller.g.dart';
class CreateBillController = _CreateBillControllerBase
with _$CreateBillController;
abstract class _CreateBillControllerBase with Store {
final appBarTitle = 'Criar Conta';
final criarConta = 'Criar conta';
final nomeDaConta = 'Nome da conta';
final seuNome = 'Seu nome';
#action
createBill(String billname, String userName) {
// here, dataSource should be given in a constructor
datasource.createBill(billName, userName);
}
}
How can I pass a DataSource (repository) as a parameter to this class?

What you need is to declare constructor for CreateBillController instead of _CreateBillControllerBase, because constructor is not inherited by child class in Dart. The simplest way is to assign the passed in datasource to the corresponding property in parent class in the constructor, as you can see in the below snippet. You can also implement a constructor for _CreateBillControllerBase as well and call super(datasource) in CreateBillController's constructor.
import 'package:mobx/mobx.dart';
part 'create_bill_controller.g.dart';
class CreateBillController extends _CreateBillControllerBase with _$CreateBillController {
// HERE! Implement constructor for CreateBillController
// Do this if you have a constructor for _CreateBillControllerBase
//
// CreateBillController(DataSource datasource) : super(datasource)
//
CreateBillController(DataSource datasource) {
super.datasource = datasource;
}
}
abstract class _CreateBillControllerBase with Store {
final appBarTitle = 'Criar Conta';
final criarConta = 'Criar conta';
final nomeDaConta = 'Nome da conta';
final seuNome = 'Seu nome';
// HERE! Declare datasource
DataSource datasource;
#action
createBill(String billname, String userName) {
datasource.createBill(billName, userName);
}
}

Related

How to listen for changes to an object's property inside a View Model using Provider in flutter?

Let's say I have the following view model class
class Foo extends ChangeNotifier{
//Object variable to which changes will be made
Object _fooObject = Object();
// Getter and Setter of Object
Object get fooObject => _fooObject;
set fooObject(Object value) {
_fooObject = value;
notifyListeners();
}
}
And let's say this is my Object Class
class Object{
int? property1;
String? property2;
Object(this.property1,this.property2);
}
Now If I assign a new Object() to fooObject the changes will easily reflect because I have called notifyListeners() in the setter but what If I change a single property in the fooObject let's say I do
Provider.of<Foo>(context).fooObject.property1 = 2;
How do I exactly detect these changes in realtime? do I have to make a separate getter setter for each property? What's the best solution to call notifyListeners() on property1's change?
you can determine using the identical(a , b) function.
set fooObject(Object value) {
if(identical(_fooObject , value)){
_fooObject = value;
notifyListeners();
}
}

How to set a function parameter's default value as an object of a class which extends an abstract class?

Let's say I have several classes which extend an abstract class. Now I want to pass a default value to a function argument, where the type of the argument is the abstract class. Dart expects a const value, and I couldn't create a const constructor for an abstract class. How can I pass a default value of the abstract class?
Sample code is as following:
class Main {
late A objOfA;
Main({ A nObjOfA = const B() }); // <===== Error here
}
abstract class A {
abstract String name;
abstract int id;
}
class B extends A {
#override
String name = "B";
#override
int id = 1;
}
class C extends A {
#override
String name = "C";
#override
int id = 1;
}
Here, how can I pass a default value of nObjOfA in the constructor of Main?
Dart expects a const value, and I couldn't create a const constructor for an abstract class.
There is no rule that you cannot create a const constructor for an abstract class. Abstract classes can have constructors; you just can't call them directly to instantiate an abstract class. The following code is legal:
class Main {
A objOfA;
Main({this.objOfA = const B()});
}
abstract class A {
const A();
abstract final String name;
abstract final int id;
}
class B extends A {
const B();
#override
final String name = "B";
#override
final int id = 1;
}
class C extends A {
#override
String name = "C";
#override
int id = 1;
}
Note that I needed to add final qualifiers since const objects must be immutable. (Unrelated, but I also fixed the inappropriate use of the late keyword.)
In general, there will be cases where you cannot create a const constructor. If you want to use an instance of that type as a default argument in such cases, you can use null as a default value and assign a non-const value later.

Flutter plugin instance with parameters

I am trying to make a plugin for authentication. It will act like a "wrapper" (but with additional functionality for each plugin) for different already existing packages for different platforms.
By the additional functionality I mean
Web implementation already has state management
Android implementation is AppAuth, so here I need to add my own state management
I am trying to use the PlatformInterface way, but I cannot find any guide how to make it instantiable with constructor params.
Let's say I have this code:
abstract class KeycloakAuth extends PlatformInterface {
KeycloakAuth()
: super(token: _token);
static final Object _token = Object();
static late KeycloakAuth _instance = KeycloakAuth._setPlatform();
static KeycloakAuth get instance => _instance;
static set platform(KeycloakAuth instance) {
PlatformInterface.verifyToken(instance, _token);
_instance = instance;
}
factory KeycloakAuth._setPlatform() {
if (Platform.isAndroid) {
return KeycloakAuthAppAuth();
} else {
throw UnimplementedError('The current platform ${Platform.operatingSystem} is not supported.');
}
}
}
This would work, but in my app I would like to do this:
final _keycloakAuth = KeycloakAuth(keycloakUrl: 'xxx', clientId: 'yyy');
If I simply tried to add params like this:
abstract class KeycloakAuth extends PlatformInterface {
final String keycloakUrl;
final String clientId;
KeycloakAuth({
required this.keycloakUrl,
required this.clientId,
})
: super(token: _token);
...
I wouldn't be able to pass them inside the _setPlatform() method since this is static method.
Also KeycloakAuthAppAuth extends KeycloakAuth, so I would need to pass those parameters back and forth, like instantiate KeycloakAuth, this instantiates KeycloakAuthAppAuth which needs to pass those parameters back via super()...
Any tips for this?
I know I can make a method initialize({String keycloakUrl, String clientId}) with my parameters, but I would still like to know if it's possible to make it using the constructor.

Flutter : create new instance of a class which no have default constructor and change some properties

I have a class with name "RecognisedText" in one of my packages which is required in my Flutter application. This class is:
class RecognisedText {
RecognisedText._(this.text, this.blocks);
factory RecognisedText.fromMap(Map<dynamic, dynamic> map) {
var resText = map["text"];
var textBlocks = <TextBlock>[];
for (var block in map["blocks"]) {
var textBlock = TextBlock.fromMap(block);
textBlocks.add(textBlock);
}
return RecognisedText._(resText, textBlocks);
}
///String containing all the text identified in a image.
final String text;
///All the blocks of text present in image.
final List<TextBlock> blocks;
}
I want to define a variable from this class:
RecognisedText myobject = RecognisedText(mytext,myblocks);
but it raise this error:
The class 'RecognisedText' doesn't have a default constructor
I tried to define myobject in different way:
RecognisedText myobject;
myobject.text = mytext;
myobject.blocks = myblocks;
but it raise this error:
'text' can't be used as a setter because it's final.
How i can define my new variable from RecognisedText class and set properties? I can't change any part of class RecognisedText because it is a remote class (added from pubspec.yaml)
Edit:
I finally solved my problem with this code:
RecognisedText myobject = RecognisedText.fromMap({"text": mytext, "blocks": myblocks});
Your Class can't create its instance so try using YourClassName.fromMap constructor.
Class RecognisedText is designed in the way that you can not create its instance other than using its fromMap constructor, which accepts map.
So the only way to create it is to create map with values you need and pass it to RecognisedText.fromMap constructor.
If you already have your block and your text as variables, you can modify you class like this to accept a default constructor :
class RecognisedText {
//----Replace this line ----
//RecognisedText._(this.text, this.blocks);
//----By this line ----
RecognisedText.(this.text, this.blocks);
factory RecognisedText.fromMap(Map<dynamic, dynamic> map) {
var resText = map["text"];
var textBlocks = <TextBlock>[];
for (var block in map["blocks"]) {
var textBlock = TextBlock.fromMap(block);
textBlocks.add(textBlock);
}
return RecognisedText._(resText, textBlocks);
}
///String containing all the text identified in a image.
final String text;
///All the blocks of text present in image.
final List<TextBlock> blocks;
}
To complete Alex's answer, the constructor fromMap takes a map as a parameter. It should look like :
RecogniserdText.fromMap({'text': myText, 'blocks': myblock1, 'blocks': myblock2, 'blocks': myblock3});

How to concatenate a class with a variable to get a static variable from this class?

I am making a pokemon app and I have a question that I already had in other projects and I would like to know if anyone can help me with a solution.
I receive a variable called pokemonName from other screen, I want to pass the variable and concatenate with the class "Strings", it will be like Strings.+pokemonName.toLowerCase(), converting to lowercase to get the map from the class Strings, but I don't know how to achieve this to remove the switch and don't need to use a lot of cases for each pokemon.
class PokemonDetailScreen extends StatelessWidget {
final String pokemonName;
final String image;
Map<String, dynamic> pokemonMap = {};
PokemonDetailScreen(this.pokemonName, this.image, this.index){
getPokemonMap();
}
#override
Widget build(BuildContext context) {
return Container();
}
void getPokemonMap(){
switch(pokemonName){
case "Bulbasaur":
pokemonMap = Strings.bulbasaur;
break;
case "Charmander":
pokemonMap = Strings.charmander;
break;
}
}
}
**Class in another dart file:**
class Strings {
static Map bulbasaur = {};
}
What I needed is something like this:
void getPokemonMap(){
pokemonMap = Strings.$pokemonMap.toLowerCase();
}
What you could do is have a static map indexed by the name of your Pokemons and whose values are maps.
class Strings {
static Map<String, dynamic> map = {
'Bulbasor': {},
'Charmander': {},
// ...
};
}
And you’ll use it like this: pokemonMap = Strings.map[pokemonName].
~You can use JSON file to do all this things instead use a class.~
I recommend not use a static class to do that thing, instead you can just make a normal class and instantiate on another file, so when the class that you call your another class will be dispose when the parent was.
class PokemonStrings {
Map bulbasaur = {your map here};
}
To call that in another file you need just do
PokemonString _pokemonString = PokemonString();
And call whatever you need in the class that you instantiate
var bulbasaurMap = _pokemonString.bulbasaur;
But even so you need walk with static class. Just call the name of class followed by dot to access all the static attributes
var bulbasaurMap = PokemonString.bulbasaur;