4

product bloc class

  final ProductRepositoryImpl _productRepositoryImpl;

  ProductBloc(this._productRepositoryImpl) : super(ProductInitializing()) {
    
    on<AddToCart>((event, emit) => _addToCart(event, emit));
    on<RemoveFromCart>((event, emit) => _removeFromCart(event, emit));
  }
  Future _removeFromCart(
      RemoveFromCart event, Emitter<ProductState> emit) async {
    try {
      final state = this.state;
      if (state is ProductLoaded) {
        List<ProductModel> productList = state.products.map((pro) {
          if (pro.prodId == event.productModel.prodId) {
            if (pro.count > 0) {
              pro.count--;
            }
          }
          return pro;
        }).toList();
        emit(ProductLoaded(products: productList));
      }
    } catch (e) {
      emit(ProductError(message: "Not added to the cart"));
    }
  }

  Future _addToCart(AddToCart event, Emitter<ProductState> emit) async {
    try {
      final state = this.state;

      if (state is ProductLoaded) {
        List<ProductModel> products = state.products.map((pro) {
          if (pro.prodId == event.productModel.prodId) {
            ++pro.count;
          }

          return pro;
        }).toList();
        emit(ProductLoaded(products: products));
      }
    } catch (e, stack) {
      print("somethign wrong ${stack.toString()}");
      emit(ProductError(message: "Not added to the cart"));
    }
  }
 
}

product event class

abstract class ProductEvent extends Equatable {
  const ProductEvent();
}

class AddToCart extends ProductEvent {
  final ProductModel productModel;
  const AddToCart(this.productModel);
  @override
  List<Object> get props => [productModel];
}

class RemoveFromCart extends ProductEvent {
  final ProductModel productModel;
  const RemoveFromCart(this.productModel);
  @override
  List<Object> get props => [productModel];
}

product state class

abstract class ProductState extends Equatable {
  const ProductState();
}

class ProductInitializing extends ProductState {
  @override
  List<Object> get props => [];
}

class ProductLoading extends ProductState {
  @override
  List<Object> get props => [];
}

class ProductError extends ProductState {
  String message;
  ProductError({required this.message});
  @override
  List<Object> get props => [message];
}
class ProductLoaded extends ProductState {
  final List<ProductModel> products;

  const ProductLoaded({
    required this.products,
  });

  @override
  List<Object> get props => [products];
}

product list screen where i display the products

              builder: ((context, state) {
                final state = context.read<ProductBloc>().state;
                if (state is ProductLoaded) {
                  return SliverGrid(
                    delegate: SliverChildBuilderDelegate(
                      (context, index) {
                        return StatefulBuilder(builder: (context, setState) {
                          return ProductItem(
                            productModel: state.products[index],
                            addToCart: (product) {
                              context
                                  .read<ProductBloc>()
                                  .add(AddToCart(product));
                            },
                            removeFromCart: (product) {
                              product.count > 0 ? product.count-- : 0;
                              context
                                  .read<ProductBloc>()
                                  .add(RemoveFromCart(product));
                            },
                          );
                        });
                      },
                      childCount: state.products.length,
                    ),
                    gridDelegate:
                        const SliverGridDelegateWithFixedCrossAxisCount(
                      crossAxisCount: 2,
                      mainAxisSpacing: 1,
                      crossAxisSpacing: 1,
                      childAspectRatio: .6,
                    ),
                  );
                }
                return const SliverToBoxAdapter(child: SizedBox.shrink());
              }),
            ),

product Item class that are used inside listview

class ProductItem extends StatelessWidget {
  const ProductItem(
      {Key? key,
      required this.productModel,
      required this.addToCart,
      required this.removeFromCart})
      : super(key: key);
  final ProductModel productModel;
  final Function(ProductModel product) addToCart;
  final Function(ProductModel product) removeFromCart;
  @override
  Widget build(BuildContext context) {
    return Card(
      margin: EdgeInsets.zero,
      color: Colors.grey[50],
      elevation: 1,
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.circular(0.0),
      ),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        mainAxisAlignment: MainAxisAlignment.start,
        children: [
          SizedBox(
            height: MediaQuery.of(context).size.height * .26,
            width: double.infinity,
            child: Card(
              elevation: 0,
              margin: EdgeInsets.zero,
              semanticContainer: true,
              color: secondaryLight,
              clipBehavior: Clip.antiAliasWithSaveLayer,
              shape: RoundedRectangleBorder(
                borderRadius: BorderRadius.circular(0.0),
              ),
              child: CachedNetworkImage(
                imageUrl: productModel.prodImage ??
                    ' https://picsum.photos/250?image=9 ',
                errorWidget: (context, url, error) =>
                    Image.asset('assets/images/logo.png'),
                fit: BoxFit.cover,
              ),
            ),
          ),
          const SizedBox(
            height: 5,
          ),
          Flexible(
              child: Padding(
            padding: const EdgeInsets.only(left: 5.0),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text(
                  productModel.prodName!,
                  style: kLabelStyleBold,
                ),
                Text(productModel.prodCode!),
                Text(productModel.prodMrp!),
              ],
            ),
          )),
          Row(
            mainAxisAlignment: MainAxisAlignment.spaceAround,
            children: [
              Flexible(
                child: IconButton(
                  onPressed: () => removeFromCart(productModel),
                  icon: const Icon(Icons.remove_circle_outline),
                ),
              ),
              Builder(builder: (context) {
                context.watch<ProductBloc>().state;
                return Flexible(
                  child: Text(
                    productModel.count.toString(),
                    style: kLabelStyleBold.copyWith(
                      fontSize: 22,
                    ),
                  ),
                );
              }),
              Flexible(
                child: IconButton(
                  onPressed: () => addToCart(productModel),
                  icon: const Icon(Icons.add_circle_outline),
                ),
              ),
            ],
          ),
        ],
      ),
    );
  }
}

in product item widget there are two buttons to manage the product counter but unfortunately i am not able to get the updated list using bloc. although i can see the log of bloc that event gets executed and values are updated but when emitting the updated list it doesn't reflect on the UI, any help would be appreciated

logs when the products load and counter button hit

I/flutter ( 1527): LoadPrdoucts()
I/flutter ( 1527): product from local db 5
I/flutter ( 1527): ProductBloc Transition { currentState: ProductInitializing(), event: LoadPrdoucts(), nextState: ProductLoaded([ProductModel(), ProductModel(), ProductModel(), ProductModel(), ProductModel()]) }
I/flutter ( 1527): ProductBloc Change { currentState: ProductInitializing(), nextState: ProductLoaded([ProductModel(), ProductModel(), ProductModel(), ProductModel(), ProductModel()]) }
E/FlutterJNI( 1527): Failed to decode image
E/FlutterJNI( 1527): android.graphics.ImageDecoder$DecodeException: Failed to create image decoder with message 'unimplemented'Input contained an error.
E/FlutterJNI( 1527):    at android.graphics.ImageDecoder.nCreate(Native Method)
E/FlutterJNI( 1527):    at android.graphics.ImageDecoder.access$200(ImageDecoder.java:169)
E/FlutterJNI( 1527):    at android.graphics.ImageDecoder$ByteBufferSource.createImageDecoder(ImageDecoder.java:246)
E/FlutterJNI( 1527):    at android.graphics.ImageDecoder.decodeBitmapImpl(ImageDecoder.java:1754)
E/FlutterJNI( 1527):    at android.graphics.ImageDecoder.decodeBitmap(ImageDecoder.java:1747)
E/FlutterJNI( 1527):    at io.flutter.embedding.engine.FlutterJNI.decodeImage(FlutterJNI.java:524)
I/flutter ( 1527): AddToCart(ProductModel())
I/flutter ( 1527): AddToCart(ProductModel())
I/flutter ( 1527): AddToCart(ProductModel())
I/flutter ( 1527): RemoveFromCart(ProductModel())
I/flutter ( 1527): RemoveFromCart(ProductModel())
avinash
  • 501
  • 2
  • 8
  • 16

1 Answers1

1

In general I would make a stateful class using BLoc or Cubit. Then I would bind the class with my Bloc or Cubit class by extending like

class WorkoutsCubit extends Cubit<List> { WorkoutsCubit() : super([]); .......................... .......................... }

My workout class is reactive and stateful because

class Workout extends Equatable {
  final String? title;
  final List<Exercise> exercises;

}

Then from my WorkoutsCubit class I would call events(for Bloc) or method(for cubit)

 myEditedMethod(Workout workout, int index) {
// ignore: prefer_const_literals_to_create_immutables
Workout newWorkout = Workout(title: workout.title, exercises: []);
int exIndex = 0;
int startTime = 0;
for (var ex in workout.exercises) {
  print("...the title is ${workout.title}");
  print("...the prelude is ${ex.title}");
  newWorkout.exercises.add(Exercise(
      prelude: ex.prelude,
      title: ex.title,
      duration: ex.duration,
      index: exIndex,
      startTime: startTime));
  exIndex++;
  startTime += ex.prelude! + ex.duration!;
}
/*
because we have a list of states we we could do index
 */
state[index] = newWorkout;
print("all data is ${state.length}");
emit([...state]);

}

Call the myEditedMethod() from the using

 `BlocProvider.of<WorkoutCubits>.myEditedMethod()`

Now that's one of the ways you can update a list. More about it here https://learnflutter.co/flutter-bloc-update-item-in-the-list/

Now that's generally you update a list using BLoC or Cubit

dylan
  • 319
  • 2
  • 4