Flutter Provider integer Reset - flutter

I have a count variable like this:
class Count with ChangeNotifier {
int _count = 1;
int get count => _count;
void setCount(bool isIncrement) {
if (isIncrement) {
_count = checkCount(_count + 1);
} else {
_count = checkCount(_count - 1);
print("decrement" + _count.toString());
}
notifyListeners();
}
int checkCount(int count) {
if (count < 0) {
return 0;
} else if (count > 10) {
return 10;
} else {
return count;
}
}
}
I'm using the provider to use it on the food pages. But when I switch between the pages, the count variable continues from where it left off. I want it to restart as 1 every time the page changes.
class Hamburger extends StatefulWidget {
const Hamburger({super.key, required Count count});
#override
State<Hamburger> createState() => _HamburgerState();
}
class _HamburgerState extends State<Hamburger> {
#override
Widget build(BuildContext context) {
Color coloricon = Provider.of<iconcolor>(context).coloricon;
int count = Provider.of<Count>(context).count;
return Scaffold(
…
);
}
}

The idea of Provider is to have a consistent state across all your pages.
If you want to save only the number of hamburgers selected you need a variable similar to _hamburgerCount and control it there.
Or, for a more scalable solution, you can create a Map<String, int> or something similar to store the amount of each type. There is many ways to solve this, but with one global count variable you can not achieve storing a count for each type of food.

Related

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);
}
}

How to copy a list into another in a StateNotifier, so it update with every change

The List EleccionSinSeleccionClase is just a list of a class who has a String on it.
class EleccionSinSeleccionClase {
String Eleccion;
}
The state List is another class:
class EleccionConSleccionClase {
String Eleccion;
bool selec;
}
The problem is that I want to copy the first into the state of the StateNotifier, this line break the code.
This is the line: state[i].Eleccion = ListaElecciones[i].Eleccion;
class EleccionesConSeleccionNotifier
extends StateNotifier<List<EleccionConSleccionClase>> {
final List<EleccionSinSeleccionClase> ListaElecciones;
EleccionesConSeleccionNotifier({required this.ListaElecciones}) : super([]);
void init(){
print(ListaElecciones.length.toString());
if(ListaElecciones.length != 0){
for (int i = 0; i < ListaElecciones.length; i++) {
state[i].Eleccion = ListaElecciones[i].Eleccion; ////HERE////
}
}
}
}
final eleccionConSleccionStateNotifierProvider = StateNotifierProvider<
EleccionesConSeleccionNotifier, List<EleccionConSleccionClase>>((ref) {
final eleccioneswatch =
ref.watch(eleccionesSinSeleccionStateNotifierProvider);
return EleccionesConSeleccionNotifier(ListaElecciones: eleccioneswatch)..init();
});
Maybe the problem is that you initialize state as an empty list super([]) and then you're trying to change a value in an index that doesn't exist (state[i] where the list is obviously empty and cannot access that position)
void init(){
print(ListaElecciones.length.toString());
if(ListaElecciones.length != 0){
/// you will need to check if both lists are the same lenght if you actually want to do this
/// without failling
/*for (int i = 0; i < ListaElecciones.length; i++) {
state[i].Eleccion = ListaElecciones[i].Eleccion; ////HERE////
}*/
/// if you only want to copy Eleccion parameter in a new class this would be the easiest way
state = ListaElecciones.map((cb) => EleccionConSleccionClase(Eleccion: cb.Eleccion)).toList();
}
}

Flutter Bloc Pattern passing more than just state?

I was reading that flutter bloc pattern is best for managing state.
I can see the need to separate display and business logic into separate areas.
Trying to learn flutter/dart from ground up.
I building a listview and each row of individual items that acts as a shopping card. User can select # of items or flavors of bagels in each row.
first issue is how to display the count of variable _dozen on screen? I have cubit/bloc sample code working. Trying to add simple test logic to when use select intervals of 13 bagels it increment a count of 1 bakers = _dozen. I can see this in debugger works . But I cannot ( sorry being new ) cannot figure out how to pass the _dozen variable to my view_page. Is passing in Bloc on for state management correct? or do I fall back and try inheritabve widget?
at end of day just want to display at bottom of screen total dozen bagels order.
import 'package:bloc/bloc.dart';
/// {#template counter_cubit}
/// A [Cubit] which manages an [int] as its state.
/// {#endtemplate}
class CounterCubit extends Cubit<int> {
/// {#macro counter_cubit}
CounterCubit() : super(12);
int _dozen = 12;
/// Add 1 to the current state.
void increment() {
if (state >= 0) {
emit(state + 1);
_dozen = ( state ~/ 13);
print('dozen:' + '$_dozen');
}
}
/// Subtract 1 from the current state.
void decrement() {
if (state > 0) {
emit(state - 1);
_dozen = ( state ~/ 13);
print('dozen:' + '$_dozen');
}
}
}
It seems that you need to keep more than one int in your state; one for count and one for dozen. Make a separate class CounterState to represent your state and hold those values so you end up with this code:
import 'package:bloc/bloc.dart';
class CounterState {
int count;
int dozen;
CounterState(this.count, this.dozen);
}
/// {#template counter_cubit}
/// A [Cubit] which manages an [CounterState] as its state.
/// {#endtemplate}
class CounterCubit extends Cubit<CounterState> {
/// {#macro counter_cubit}
CounterCubit() : super(CounterState(12,1));
/// Add 1 to the current state.
void increment() {
if (state.count >= 0) {
final int count = state.count + 1;
emit(CounterState(count, count ~/ 12));
print('dozen:' + '${state.dozen}');
}
}
/// Subtract 1 from the current state.
void decrement() {
if (state.count > 0) {
final int count = state.count - 1;
emit(CounterState(count, count ~/ 12));
print('dozen:' + '${state.dozen}');
}
}
}
Then in your Widgets, access this as state.count and state.dozen instead of just state.
This solution can be improved, but it is sufficient to get you going.

Why can't I set a dynamic property inside a nested function?

I'm trying to create a function that can dynamically set the properties on an object like so:
void main() {
final obj = Item();
obj.update(5);
print(obj.xVal);
}
class ObjectBase {
void _setData(current, newValue) {
current = newValue;
print(current);
}
}
class Item extends ObjectBase {
int _x;
int get xVal => _x;
update(x) {
_setData(_x, x);
}
}
The print statement in _setData works fine, but it doesn't actually appear to change _x, even if it has been passed through. I expected that changing the reference here would update it everywhere.
So why isn't this working and is there a fix?
You can assume that I do have good reason to be calling _setData inside update rather than just implementing the functionality in update.
Update:
A real life example of what i'm trying to achieve
class ViewModel extends ChangeNotifier {
void _setDataFromDependency(current, newValue) {
if (!deepDynamicEquality(current, newValue)) {
current = newValue;
notifyListeners();
}
}
}
class ListScreenViewModel extends ViewModel {
int _localCount = 0;
List<int> _globalList;
ListScreenViewModel();
List<int> get globalList => _globalList;
int get localCount => _localCount;
incrementLocal() {
_localCount++;
notifyListeners();
}
void update(ListStore listStore) {
_setDataFromDependency(_globalList, listStore.globalList);
// if (!deepDynamicEquality(_globalList, listStore.globalList)) {
// _globalList = listStore.globalList;
// notifyListeners();
// }
}
}
An oversimplified workaround is to return the value from _setData . #julemand101 has already answered limitations.
class ObjectBase {
int _setData(current, newValue) {
current = newValue;
print('current: $current');
return current;
}
}
class Item extends ObjectBase {
int _x;
int get xVal => _x;
update(x) {
_x = _setData(_x, x);
}
}

Using List to store and find class element with random member variable

I want to store a class in a List to later retrieve the value. Now the problem I
m having is that one of the members is a random value. So when trying to retrieve the entry I can't find it, since I can't produce the 'key'.
I'm happy for suggestions on implementing this in a different way.
So this is the example class I want to store in a list:
class MyDevice{
int device;
int randomNumber;
void set(int device, int random){
this.device = device;
this.randomNumber = random;
}
}
class Handling{
final List<MyDevice> myDevicesList = new List<MyDevice>();
...
...
MyDevice dev = new MyDevice();
dev.set(device, random);
//Store entry into List
myDevicesList.add(dev);
...
...
Now I want to delete or possibly replace an entry, but I will have no way of
finding it since the random value is not known after storing above.
// Note that I have the device value supplied in a call-back, for the sake of this
// example let's just define a method for removing
void removeEntry(int device){
MyDevice dev = new MyDevice();
dev.set(device, );
myDevicesList.remove(dev);
}
How can I find / remove an entry that is a class and I only want to 'search' the list with one of the embers in the class that is stored?
Is the only solution to walk the list and make my own compare method to identify the entry by the 'device' member?
All you need is the removeWhere List method. You have to remove where MyDevice.device matches the argument, device.
Here's the code you requested for
void removeEntry(device) {
myDevicesList.removeWhere((element) => element.device == device);
}
Here's the full code.
import 'dart:math';
class MyDevice {
int device;
int randomNumber;
void setValue(int device, int random) {
this.device = device;
this.randomNumber = random;
}
}
class Handling {
final List<MyDevice> myDevicesList = new List<MyDevice>();
void addToList(device, random) {
MyDevice dev = new MyDevice();
dev.setValue(device, random);
myDevicesList.add(dev);
}
void removeEntry(device) {
myDevicesList.removeWhere((element) => element.device == device);
}
List<MyDevice> get list {
return myDevicesList;
}
}
void main() {
final handle = new Handling();
handle.addToList(2, Random().nextInt(5));
handle.addToList(18, Random().nextInt(4));
handle.addToList(12, Random().nextInt(9));
print("List before ${handle.list.map((element) {
return [element.device, element.randomNumber];
})}");
handle.removeEntry(18);
print("List after ${handle.list.map((element) {
return [element.device, element.randomNumber];
})}");
}
The output is
List before ([2, 1], [18, 0], [12, 7])
List after ([2, 1], [12, 7])
Here's the solution on dartpad
You don't know random value, so you have to manually compare and remove item from list.
Following code may help you.
In following example i added 1,2 and 5 and remove 2 after that you can see in print only 1 and 5.
class MyDevice {
int device;
int randomNumber;
void set(int device, int random) {
this.device = device;
this.randomNumber = random;
}
}
class Delet2 extends StatefulWidget {
#override
_Delet2State createState() => _Delet2State();
}
class _Delet2State extends State<Delet2> {
final List<MyDevice> myDevicesList = new List<MyDevice>();
#override
void initState() {
super.initState();
add(1);
add(2);
add(5);
delete(2);
for (int k = 0; k < myDevicesList.length; k++) {
print(myDevicesList[k].device);
}
}
add(int number) {
MyDevice dev = new MyDevice();
dev.set(number, Random().nextInt(1000));
myDevicesList.add(dev);
}
delete(int number) {
for (int i = 0; i < myDevicesList.length; i++) {
if (myDevicesList[i].device == number) {
myDevicesList.removeAt(i);
}
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(),
);
}
}