Flutter Riverpod StateNotifier to not add to end of List - flutter

im new to Riverpod and Flutter
the problem i'm having is that when i use StateNotifier, the state is immutable so i have to create new state and add new value to the end of List
void add(Cart cart) {
state = [...state, cart];
}
void inQuan(int i) {
final tempCart = state[i];
tempCart.quantity++;
remove(state[i]);
add(tempCart);
}
and this makes my list pushes the item i'm editing to the end
is there any way to optimize my code?

This creates only one new array.
void inQuan(int i) {
state = [
for (int index = 0; i < state.length; index++)
if (i == index)
state[i].copyWith(quantity: state[i].quantity++)
else
state[i]
];
}

Related

Flutter Provider integer Reset

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.

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.

Is it possible to create widgets within the build method by using for loops?

I want to make a non scrollable grid that in it's whole expands to it's parent. I am trying to run a for loop in the build method to create the rows and columns. But I get the following errors
The element type 'Set<Row>' can't be assigned to the list type 'Widget'.
and
The element type 'Set<Text>' can't be assigned to the list type 'Widget'.
from the for loop. Why is this? And how can I fix this?
import 'package:flutter/material.dart';
class ExpandingGridArguments{
List<Widget> tiles;
int columns;
int rows;
ExpandingGridArguments(List<Widget> tiles, int columns)
{
this.tiles = tiles;
this.columns = columns;
this.rows = (tiles.length / columns).ceil();
}
}
class StaticGrid extends StatelessWidget {
#override
Widget build(BuildContext context) {
final ExpandingGridArguments arguments = ModalRoute.of(context).settings.arguments;
return Column(
children:
[
for(int c = 0; c < arguments.rows; c++ )
{
Row
(
children :
[
for(int r = 0; r < arguments.columns; r++)
{
Text('A row'),
}
]
),
}
]
);
}
}
The syntax of for inside lists is slightly different from what you did.
Instead of:
[
for (var i = 0; i < 42; i++) {
Text('$i')
}
]
it is used without the {}:
[
for (var i = 0; i < 42; i++)
Text('$i')
]
The reason for this being that {} is also used to create Set/Map:
Set<int> hashSet = {};
As such, using {} inside lists for readability is not supported, because Dart would confuse a "block" with the creation of a Set
You could create a function outside the build method to do the for loop and return the widgets
import 'package:flutter/material.dart';
class ExpandingGridArguments{
List<Widget> tiles;
int columns;
int rows;
ExpandingGridArguments(List<Widget> tiles, int columns)
{
this.tiles = tiles;
this.columns = columns;
this.rows = (tiles.length / columns).ceil();
}
}
class StaticGrid extends StatelessWidget {
buildRows(ExpandingGridArguments arguments) {
List<Widget> row = new List();
for(int c = 0; c < arguments.rows; c++ )
{
row.add(
Row
(
children :
[
for(int r = 0; r < arguments.columns; r++)
{
Text('A row'),
}
]
)
)
}
return row;
}
#override
Widget build(BuildContext context) {
final ExpandingGridArguments arguments = ModalRoute.of(context).settings.arguments;
return Column(
children: buildRows(arguments)
);
}
}
Personally, I find it a lot cleaner.
The reason for your errors is because for loops are done differently inside the build method. What you are doing is creating a Set

javafx8 candle stick chart can't getrid of the stale data

I used the sample candle stick chart code to draw chart. When I worked in the java7 ,the chart worked fine. But when I tried in the Java8. there is a problem.
I tracked the problem like this:this code is from the sample code of Ensemble :CandlStickChart.java
#Override protected void layoutPlotChildren() {
// we have nothing to layout if no data is present
if(getData() == null) return;
// update candle positions
for (int seriesIndex=0; seriesIndex < getData().size(); seriesIndex++) {
Series<Number,Number> series = getData().get(seriesIndex);
Iterator<Data<Number,Number>> iter = getDisplayedDataIterator(series);
Path seriesPath = null;
if (series.getNode() instanceof Path) {
seriesPath = (Path)series.getNode();
seriesPath.getElements().clear();
}
while(iter.hasNext()) {
System.out.println(i++); // the different place
Data<Number,Number> item = iter.next();
double x = getXAxis().getDisplayPosition(getCurrentDisplayedXValue(item));
double y = getYAxis().getDisplayPosition(getCurrentDisplayedYValue(item));
Node itemNode = item.getNode();
CandleStickExtraValues extra = (CandleStickExtraValues)item.getExtraValue();
if (itemNode instanceof Candle && extra != null) {
Candle candle = (Candle) itemNode;
this is part of the code.the problem is with the "the different palce"
for the iter.hasNext() will preserve the stale value.so, every time I set in new data。the list is further long .
the setdata code like :
ObservableList<XYChart.Data<Number, Number>> newData
= FXCollections.<XYChart.Data<Number, Number>>observableArrayList();
for (int j = 1; j <= leno; j++) {
newData.add(。。。。。。。);//
series.getData().clear();
series.setData(newData);
When I remove the stale data by Iter.remove the exception is:we don't support removeing items from the diplayed data list.
You have to add two calls to removeDataItemFromDisplay to the dataItemRemoved method.
Note: I made series and item final in the example code.
#Override
protected void dataItemRemoved(final Data<Number, Number> item,
final Series<Number, Number> series) {
final Node candle = item.getNode();
if (shouldAnimate()) {
// fade out old candle
FadeTransition ft = new FadeTransition(Duration.millis(500), candle);
ft.setToValue(0);
ft.setOnFinished(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent actionEvent) {
getPlotChildren().remove(candle);
removeDataItemFromDisplay(series, item);
}
});
ft.play();
} else {
getPlotChildren().remove(candle);
removeDataItemFromDisplay(series, item);
}
}