How to pass values to another screen with flutter bloc - flutter

how to know pass values for calculation Bmi of User like (height of user gender and age and weight) but with BLoC I want to know passing this information from BmiModule
to ResultModule
Note: I use Cubit to pass for BmiModule, but I can't pass value like isMale to ResultModule.
This is my code
class BmiCubit extends Cubit<BmiStates> {
BmiCubit() : super(BmiInitialState());
// this value to use in selecting what is the gender of the user
bool isMale = false;
// value of height
int heightValue = 175;
// value of weight
int weightValue = 70;
// value of age
int ageValue = 20;
// It use to view variables like isMale in BmiModule but I can use it //to pass
// I try to passing but do not work
static BmiCubit get(BuildContext context) => BlocProvider.of(context);
}
I want to pass data to make some processing Bmi of user.
And thanks

Related

My boolean bloc state variable stops changing after the first reassignment

I am relatively new at flutter. I am creating a timer app using bloc. In the timer you are supposed to have a session, then a break and so on and so forth. To track which type of session to start(a break or session), I am using a boolean value isBreak which I am tracking in the SessionsBloc.
Here is the definition of the SessionsState:
part of 'sessions_bloc.dart';
abstract class SessionsState extends Equatable { final bool isBreak; final int sessionCount; const SessionsState(this.isBreak, this.sessionCount);
#override List<Object> get props => []; }
class SessionsInitial extends SessionsState { const SessionsInitial(super.isBreak, super.sessionCount); }
class SessionTrackingState extends SessionsState { const SessionTrackingState(super.isBreak, super.sessionCount); }
I then use A BlocListener to check for the TimerFinishedState from another bloc TimerBloc, after which I add an event, SessionTrackingEvent, that is supposed to change the aforementioned boolean value.
Here is the code for the listener:
listener: (context, state) {
Task currentTask =
BlocProvider.of<TasksBloc>(context).state.currentTask;
bool isTimeBoxed = currentTask.isTimeBoxed;
int sessionDuration;
int breakDuration;
if (state is TimerCompleteState) {
//Get the SessionsBloc state
final sessionState = BlocProvider.of<SessionsBloc>(context).state;
//Get the current value of the isBreak boolean value
bool isBreak = sessionState.isBreak;
int sessionCount = sessionState.sessionCount;
//Print statements: Can't Debug properly yet:(
print(sessionState.isBreak);
print(sessionState.sessionCount);
if (isTimeBoxed) {
sessionDuration = currentTask.sessionTimeBox!;
breakDuration = currentTask.breakTimeBox ?? 2;
// sessionCount = HiveDb().getTaskSessionCount(currentTask.taskName);
} else {
sessionDuration = 5;
breakDuration = 3;
}
if (isBreak) {
//Set timer with duration time
BlocProvider.of<TimerBloc>(context)
.add(InitializeTimerEvent(duration: sessionDuration));
//Add Event to track session count and next countdown if break or session
BlocProvider.of<SessionsBloc>(context).add(SessionTrackingEvent(
isBreak: isBreak,
sessionCount: sessionCount,
));
} else {
//Add event to reset timer
BlocProvider.of<TimerBloc>(context)
.add(InitializeTimerEvent(duration: breakDuration));
//Emit a state that notifies Button Bloc that it's a break and deactivate repeat button.
BlocProvider.of<TimerBloc>(context)
.add(OnBreakEvent(duration: breakDuration));
//Add Event to track session count and next countdown if break or session
BlocProvider.of<SessionsBloc>(context).add(SessionTrackingEvent(
isBreak: isBreak,
sessionCount: sessionCount += 1,
));
}
}
},
Finally, in the SessionsBloc, I only have super constructor which initializes the boolean value to false and one event handler that is supposed to change it as appropriate.
class SessionsBloc extends Bloc<SessionsEvent, SessionsState> {
SessionsBloc() : super(const SessionsInitial(false, 0)) {
on<SessionTrackingEvent>((event, emit) {
emit(SessionTrackingState(
event.isBreak ? false : true, event.sessionCount));
});
}
}
The expected result is that for each SessionTrackingEvent added, the boolean should be toggled to the opposite value. However, what actually happens is that it Works the first time, turning the initialized value of false to true and from there it just stays the same. Here is a screenshot of my print statement which outputs the value of IsBreak after every call to SessionTrackingEvent.
Here is a screenshot of my print statement which outputs the value of IsBreak after every call to SessionTrackingEvent.
I have tried changing the variable type from final because I thought maybe it's a flutter constraint about reassigning variables.
I have tried moving the reading of the block state value into the build method outside of the listener because I thought maybe it doesn't read the value as frequently.
What could be the problem, what might be preventing the value from changing as appropriate?
You forgot to pass your SessionsState properties into props list, so the Bloc can't differentiate between old and new states without it.
abstract class SessionsState extends Equatable {
final bool isBreak;
final int sessionCount;
const SessionsState(this.isBreak, this.sessionCount);
#override
List<Object> get props => [isBreak, sessionCount]; // your props should go here like this
}

Flutter: In RiverPod , how to alter state model's variables directly?

I am currently learning River Pod and also new to flutter.
When setting new state in StateNotifer , I need to create a new model and replace the state
But directly changing is not working
class CounterModel {
CounterModel(this.count, this.age);
int count;
int age;
}
class CounterNotifier extends StateNotifier<CounterModel> {
CounterNotifier() : super(_initialValue);
static CounterModel _initialValue = CounterModel(0,18);
void increment() {
// state.count = state.count + 1; // not working, but need like this !
state = CounterModel(state.count + 1, state.age); // working
}
}
In the above code , when I trying to change the count variable directly like, state.count = state.count + 1 , nothing changed
But when reinitialising the state by creating a new model like state = CounterModel(state.count + 1, state.age)
Its seems to be state model variables are immutable and needs to be recreated on every alteration !
My question is , what if the CounterModel have 50 variables , then I have to do something like
state = CounterModel (var1,var2,......,var49,var50) ;
So , is it possible to directly change the variables like
state.var1 = new_value1;
state.var2 = new_value2;
....
state.var50 = new_value50;
You have to always reassign the state in StateNotifier for Consumers to see the changes hence, state.var1 = new_value1; can't work with StateNotifier
If You're very keen about that syntax, use ChangeNotifier since it allows you change individual properties of the class but you must call notifyListeners
Like so:
class CounterNotifier extends StateNotifier {
static CounterModel value = CounterModel(0,18);
void increment() {
value.count = value.count + 1;
notifyListeners();
}
}
If You want to stick with StateNotifier and don't want to write boilerplate code, create a copyWith method on the model.
Like so:
class CounterModel {
CounterModel(this.count, this.age);
int count;
int age;
CounterModel copyWith({int? count, int? age}){
return CounterModel(
count ?? this.count,
age ?? this.age
);
}
}
Then you can keep reassigning with it like so:
class CounterNotifier extends StateNotifier<CounterModel> {
CounterNotifier() : super(_initialValue);
static CounterModel _initialValue = CounterModel(0,18);
void increment() {
state = state.copyWith(count: state.count + 1);
}
}

Flutter Dart: Dynamic Relationship inside Model Class Field

I've used Laravel, where we can define relationships inside the model itself. So is that possible in Dart/Flutter?
I've built this Cart Model where Grand-total should be dynamic.
So whenever I create an instance of this Cart Model, grand total will be auto-calculated once we enter the total & discount. until then the default value 0.
code from the image above:
class Cart {
Cart({
this.total = 0,
this.discount = 0,
this.grandTotal, // I want this field dynamic: (grandtotal = total - discount)
});
int total;
int discount;
int? grandTotal;
}
define a getter method to calculate grandTotal.
Sample code:
int? get grandTotal {
// TODO: check for null cases here
return total - discount;
}

flutter add method was called on null using provider

Hello I want to add some value to my list. I have already googled for solutions but I can't see any other solutions besides initializing the list which I did.
When I try to add an item to my AutomaticDateList class I get the error:
The method 'add' was called on null.
Receiver: null
Tried calling: add(Instance of 'AutomaticDate')
Here is the class with the list in it.
class AutomaticDateList with ChangeNotifier {
List<AutomaticDate> items = []; // here I inialize
AutomaticDateList({this.items});
void addToList(AutomaticDate automaticDate) {
items.add(automaticDate);
notifyListeners();
}
List<AutomaticDate> get getItems => items;
}
This is the item I want to add to the list.
class AutomaticDate with ChangeNotifier {
String date;
String enterDate;
String leaveDate;
String place;
AutomaticDate({this.date, this.enterDate, this.leaveDate, this.place});
Here I call the method using the provider inside a page widget
void onGeofenceStatusChanged(Geofence geofence, GeofenceRadius geofenceRadius,
GeofenceStatus geofenceStatus) {
geofenceController.sink.add(geofence);
AutomaticDate automaticDateData = AutomaticDate();
automaticDateData.place = geofence.id;
automaticDateData.date = DateFormat("dd-mm-yyyy").format(DateTime.now());
if (geofenceStatus == GeofenceStatus.ENTER) {
widget.enterDate = DateFormat("HH:mm:ss").format(DateTime.now());
} else {
automaticDateData.leaveDate =
DateFormat("HH:mm:ss").format(DateTime.now());
automaticDateData.enterDate = widget.enterDate;
widget.list.add(automaticDateData);
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
AutomaticDateList automaticDateList =
Provider.of<AutomaticDateList>(context, listen: false);
automaticDateList.items.add(automaticDateData); // Here I add the data and get error "add was called on null"
print(automaticDateList.getItems);
});
}
}
The problem is in the initialization:
List<AutomaticDate> items = []; // here I inialize
AutomaticDateList({this.items});
You set a default value, but you are using the "auto-assign" sintax in the constructor, saying that items passing in the parameters are going to be assigned in the items property of the class.
You are instantiating the class using this code:
AutomaticDate automaticDateData = AutomaticDate();
So, you are passing "null" implicitly as parameter, then items [] got replaced with null value.
Just change the code to:
List<AutomaticDate> item;
AutomaticDateList({this.items = []}); // Default value

How to observe ObservableList item properties changes

I'm building a shopping app in Flutter using MVC pattern and mobx for app state management.
At the moment, I have a mobx store for cart items and one store for the cart controller.
The cart controller has a ObservableList of cart items and problem is that I don't know if there's a way of observing changes on cart items.
For instance, I'd like to observe cartItem.title or cartItem.total.
Is there a way to track this with ObservableList?
And whats is .observe() method the observable list has? (Think the documentation wasn't clear for me)
UPDATE: SAMPLE CODE
As I said I have to mobx sotres, one for the cart item and for the cart itself.
In the cart item store:
import 'package:mobx/mobx.dart';
part 'cart-item.model.g.dart';
class CartItemModel = _CartItemModel with _$CartItemModel;
abstract class _CartItemModel with Store {
int id;
String title;
String price;
String description;
#observable
int _quantity = 0;
#observable
double _total = 0;
_CartItemModel({
this.id,
this.title,
this.price,
this.description,
}) {
reaction(
(_) => _quantity,
(quantity) {
getTotal();
},
);
}
getItemQuantity() => _quantity.toString(); // Return item quantity
#action
increase() {
// Increase item quantity
if (_quantity <= 99) {
_quantity++;
}
}
#action
decrease() {
// Decrease item quantity
if (_quantity > 0) {
_quantity--;
}
}
#action
getTotal() {
// Return total price by item quantity
_total = double.parse(price) * _quantity;
return _total.toString();
}
}
And then in the cart controller:
import 'package:faccioo_user_app/models/cart-item.model.dart';
import 'package:mobx/mobx.dart';
part 'cart.controller.g.dart';
class CartController = _CartController with _$CartController;
abstract class _CartController with Store {
#observable
ObservableList<CartItemModel> cartItems = ObservableList<CartItemModel>();
#action
addItem(CartItemModel item) {
cartItems.insert(0, (item));
item.increase();
}
#action
removeItem(CartItemModel item) {
cartItems.removeWhere((cartItem) => cartItem.id == item.id);
getTotal();
}
#action
getSubtotal() {
cartItems.forEach((item) {
subtotal = subtotal + double.parse(item.getTotal());
});
return subtotal.toString();
}
#action
getTotal() {
total = (subtotal + shippingFee + serviceFee + change) - discount;
return total.toString();
}
}
The view is not being notified by the changes in cartItem.total, for example?. How do I observe changes in cartItemModel.total from ObservableLis?
To be more clear I got this print in which we can see that cart item quantity and total increase, therefore CartItemModel reactivity is working fine, but the cart controller can't track those changes from ObservableList, then the controller is not updating the view.
I'd really appreciate links and references from where I can learn more about mobx with Flutter and observable lists.
Cart view with cart item
this is an old question but I will share the hints for the solution and how to improve it.
You don't need to create a store for the model, just wrap the properties with #observable, #computed, etc.
Actions are meant to write to the store and update the store properties. If you want to read properties, just write a simple get property without the #action annotation, or if you want to read a property based on other #observable properties, use the get with #computed.
The store should be only the CartController in which you should have a #computed property that will change based on other properties changes, e.g. for the CartController store:
The CartItemModel should be transformed into a simple data class with getters and setters and is the store that will manage its state.
I didn't check in terms of types .. etc.., the getters are missing the return types, only the setters that don't need return type.
#computed
double get total() => subtotal + shippingFee + serviceFee + change - discount;
#computed
double get subtotal() {
double subTotalAggregator = 0;
cartItems.forEach((item) {
subTotalAggregator += double.parse(item.getTotal());
});
return subTotalAggregator;
}