اذهب إلى المحتوى

السؤال

نشر

حاولت كثيرا لكن للأسف لم تعمل، عندي بالصفحة الرئيسية تظهر ال categories 

أريد عند الضغط على أي category تظهر ال products الخاصة فيه تحت في نفس الشاشة ( يعني ما في navigation ) حسب الصورة المرفقة

ملاحظة / ال data جاية من API

 

photo5470088920080430557.jpg

Recommended Posts

  • 1
نشر

هناك طريقة وهي استخدام StreamController بحيث هي طريقة من طرق إدارة الحالة في فلاتر. و الأمر معقد جداً و يجب أن تكون على دراية جيدة بكيفية استخدام StreamController. لاحظ بأنه يجب أن تقوم بتعلم StreamController حتى تفهم الإجابة جيداً لأنه في الوهلة الأولى ستجد أن الأمر قد يكون فيه صعوبة 

يمكنك إنشاء ملف وليكن مسؤول عن التنصت على أي حدث جديد و يعكسه على الواجهة أي يقوم بتنفيذ هذا الحدث على الواجهة و الميزة في ذلك إنها تقوم بتنفيذ الحدث بدون اللجوء إلى بناء نفسها من الصفر و هذا الملف فليكن اسمه StreamProductsBloc.dart ويمكننا تعريف عدة متغيرات في هذا الملف بهذا الشكل 

  List<ProductsModel>? products;

  final StreamController<List<ProductsModel>> _productsController = StreamController<List<ProductsModel>>.broadcast();
  final StreamController<int> _categoryController = StreamController<int>.broadcast();

  Stream<List<ProductsModel>> get productsStream => _productsController.stream;

  StreamSink<int> get fetchProducts => _categoryController.sink;
  Stream<int> get getProductsForCategoriescategory => _categoryController.stream;

  APIService? apiService;

  int categoryID = 0;
List<ProductsModel>? products;

بحيث أول شيء نقوم بتعريف الكلاس مودل الخاص بالمنتجات.

final StreamController<List<ProductsModel>> _productsController = StreamController<List<ProductsModel>>.broadcast();

و من ثم نقوم بتعريف StreamController ليقوم بالتحكم في العملية , ويتم توفير واجهات مختلفة لإنشاء تدفقات أحداث متنوعة.

final StreamController<int> _categoryController = StreamController<int>.broadcast();

وحدة تحكم حيث يمكن الاستماع إليه أكثر من مرة .

Stream<List<ProductsModel>> get productsStream => _productsController.stream;

ثم نقوم بالحصول على البث للمراقبة.

StreamSink<int> get fetchProducts => _categoryController.sink;

ثم نقوم بإدخال حدث إضافي عن طريق StreamSink. 

StreamProductsBloc()
  {
    //this.categoryID = categoryID;
    this.products = [];
    apiService = APIService();
    _productsController.add(products!);
    _categoryController.add(this.categoryID);
    _categoryController.stream.listen(_fetchCategoriesFromApi);
  }

  Future<void> _fetchCategoriesFromApi(int category) async {
    this.products = await apiService!.getProductsForCategories(category);
    _productsController.add(this.products!);
  }

  @override
  void dispose(){
    _productsController.close();
    _categoryController.close();
  }

نقوم بإنشاء دالة جلب بيانات التصنيف عند تمرير id التصنيف و نقوم بإرجاع جميع المنتجات و من ثم نقوم بإضافة هذه البيانات إلى وحدة التحكم.

Future<void> _fetchCategoriesFromApi(int category) async {
    this.products = await apiService!.getProductsForCategories(category);
    _productsController.add(this.products!);
}

 ثم نقوم بإضافة المنتجات و id التصنيف إلى وحدة التحكم في دالة StreamProductsBloc ثم نقوم بمراقبة الحدث عن طريق استخدام listen 

StreamProductsBloc()
  {
    //this.categoryID = categoryID;
    this.products = [];
    apiService = APIService();
    _productsController.add(products!);
    _categoryController.add(this.categoryID);
    _categoryController.stream.listen(_fetchCategoriesFromApi);
  }

ثم نقوم بإنشاء ملف واجهة عرض البيانات وليكن مثلاً باسم products_screen.dart و نقوم أولاً بإنشاء نسخة جديدة من الملف الذي قمنا بإنشائه مسبقاً 

StreamProductsBloc streamProductsBloc = StreamProductsBloc();

ثم ننشأ عدة متغيرات و نعرف TabController لوضع التصنيفات في هذه TabController

bool get wantKeepAlive => true;

HelperApi helperApi = new HelperApi();
int currentIndex = 0;
late TabController _tabController;

ثم نقوم بصنع Widget خاصة بعرض التصنيفات في TabController 

Widget _categories(List<CategoryModel> categoryModel, BuildContext context) {
    _tabController = TabController(
      initialIndex: 0,
      length: categoryModel.length,
      vsync: this,
    );
    return Scaffold(
      appBar: AppBar(
        title: Text(S.of(context).products),
        bottom: TabBar(
          indicatorColor: Color(0XFF117182),
          indicatorWeight: 5,
          controller: _tabController,
          tabs: _tabs(categoryModel),
          isScrollable: true,
          onTap: (int index) {
            streamProductsBloc.fetchProducts
                .add(this.productsCategories[index].id!);
          },
        ),
      ),
      body: Container(
        child: StreamBuilder(
          stream: streamProductsBloc.productsStream,
          builder: (context, AsyncSnapshot<List<ProductsModel>>? snapshot) {
            switch (snapshot!.connectionState) {
              case ConnectionState.none:
                // ignore: todo
                // TODO: Handle this case.
                return Center(
                  child: CircularProgressIndicator(),
                );
              case ConnectionState.waiting:
                // ignore: todo
                // TODO: Handle this case.
                return ShimmerGrid();
              case ConnectionState.done:
              case ConnectionState.active:
                // ignore: todo
                // TODO: Handle this case.
                if (snapshot.hasError) {
                  return Center(
                    child: ShimmerGrid(),
                  );
                } else {
                  if (!snapshot.hasData) {
                    return ShimmerGrid();
                  } else {
                    return _drawProducts(snapshot.data!, context);
                  }
                }
            }
          },
        ),
      ),
    );
  }

لاحظ أننا نقوم بجلب منتجات كل تصنيف عند الضغط عليها عن طريق استخدام id هذا التصنيف 

streamProductsBloc.fetchProducts.add(this.productsCategories[index].id!);

و من ثم نقوم بإضافة هذا الحدث إلى streamProductBloc . 

ثم نقوم برسم Widget الخاص بالمنتجات 

Widget _drawProducts(List<ProductsModel> products, BuildContext context) {
    final cart = Provider.of<Cart>(context, listen: false);
    var initModel = Provider.of<InitModel>(context, listen: false,);
    var auth = Provider.of<AuthProvider>(context, listen: false);
    return Consumer<WishListProvider>(
        builder: (BuildContext context, wishListData, child) {
    return Container(
      padding: EdgeInsets.only(top: 24),
      child: Column(
        children: [
          Flexible(
            child: GridView.builder(
              gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
                  maxCrossAxisExtent: 200,
                  childAspectRatio: 1 / 2,
                  crossAxisSpacing: 20,
                  mainAxisSpacing: 20),
              itemCount: products.length,
              itemBuilder: (context, index) {
                return Card(
                  clipBehavior: Clip.hardEdge,
                  elevation: 0.9,
                  child: AnimationConfiguration.staggeredList(
                    position: index,
                    duration: const Duration(milliseconds: 375),
                    child: SlideAnimation(
                      verticalOffset: 50.0,
                      child: FadeInAnimation(
                        child: Padding(
                          padding: const EdgeInsets.all(8.0),
                          child: InkWell(
                            onTap: () {
                              _gotoSingleProduct(products[index], context);
                            },
                            child: Column(
                              crossAxisAlignment: CrossAxisAlignment.start,
                              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                              children: [
                                Expanded(
                                  // ignore: unnecessary_null_comparison
                                    child: Stack(
                                      children: [
                                        (products[index].images![0].src != null)
                                            ? Image.network(
                                          products[index].images![0].src!,
                                          width:
                                          MediaQuery
                                              .of(context)
                                              .size
                                              .width,
                                          height: MediaQuery
                                              .of(context)
                                              .size
                                              .height,
                                          fit: BoxFit.cover,
                                        )
                                            : Image.asset(
                                          "assets/images/1.jpeg",
                                          width:
                                          MediaQuery
                                              .of(context)
                                              .size
                                              .width,
                                          height: MediaQuery
                                              .of(context)
                                              .size
                                              .height,
                                          fit: BoxFit.fill,
                                        ),
                                        Positioned.directional(
                                          textDirection: Directionality.of(
                                              context),
                                          child: Container(
                                            margin: EdgeInsets.symmetric(
                                                horizontal: 12.0,
                                                vertical: 10.0),
                                            decoration: BoxDecoration(
                                                color: Colors.grey[200],
                                                borderRadius:
                                                BorderRadius.circular(50.0)),
                                            child: IconButton(
                                              icon: Icon(
                                                  Icons.favorite_outline),
                                              onPressed: () {
                                                //wishListData.getCount(products[index].id!, auth.id!);
                                                wishListData.addNewWishList(
                                                    price: products[index]
                                                        .price!
                                                        .toString(),
                                                    product: products[index]
                                                        .name!,
                                                    image: products[index]
                                                        .images![0]
                                                        .src!,
                                                    productId: products[index]
                                                        .id,
                                                    userId: auth.id);
                                                ScaffoldMessenger.of(context)
                                                    .showSnackBar(
                                                  SnackBar(
                                                    content: Text(
                                                      S
                                                          .of(context)
                                                          .add_product_to_wishlist,
                                                    ),
                                                    duration: Duration(
                                                        seconds: 2),
                                                  ),
                                                );
                                              },
                                              iconSize: 20.0,
                                            ),
                                          ),
                                        )
                                      ],
                                    )
                                ),
                                Padding(
                                  padding: const EdgeInsets.all(8.0),
                                  child: Text(
                                    products[index].name!.substring(0, 10),
                                    style: TextStyle(
                                      color: Colors.black,
                                      fontWeight: FontWeight.bold,
                                      fontSize: 18.0,
                                    ),
                                  ),
                                ),
                                Row(
                                  crossAxisAlignment: CrossAxisAlignment.start,
                                  mainAxisAlignment:
                                  MainAxisAlignment.spaceBetween,
                                  children: [
                                    Padding(
                                      padding: const EdgeInsets.all(8.0),
                                      child: Text(initModel.currency! +
                                          products[index].price!,
                                        style: TextStyle(
                                          color: Colors.black,
                                          fontSize: 15.0,
                                        ),
                                      ),
                                    ),
                                    IconButton(
                                      icon: Icon(
                                          Icons.add_shopping_cart_outlined),
                                      onPressed: () {
                                        //if(auth.status == Status.Authenticated){
                                        cart.addItem(
                                            products[index].id.toString(),
                                            10.0,
                                            products[index].name!.toString(),
                                            products[index].images![0].src!,
                                            1,
                                            products[index].id.toString());
                                        ScaffoldMessenger.of(context)
                                            .hideCurrentSnackBar();
                                        ScaffoldMessenger.of(context)
                                            .showSnackBar(
                                          SnackBar(
                                            content: Text(
                                              S
                                                  .of(context)
                                                  .product_added_to_the_cart,
                                            ),
                                            duration: Duration(seconds: 2),
                                            action: SnackBarAction(
                                              label: S
                                                  .of(context)
                                                  .undo,
                                              onPressed: () {
                                                cart.reomveSingleItem(
                                                    products[index]
                                                        .id
                                                        .toString());
                                              },
                                            ),
                                          ),
                                        );
                                      },
                                    ),
                                  ],
                                ),
                                Text(products[index].stockStatus!,
                                  style: TextStyle(
                                    color: Colors.orange,
                                    fontWeight: FontWeight.bold,
                                    fontSize: 15,
                                  ),),
                                Row(
                                  crossAxisAlignment: CrossAxisAlignment.start,
                                  mainAxisAlignment: MainAxisAlignment.start,
                                  children: [
                                    RatingBar.builder(
                                      initialRating: products[index]
                                          .ratingCount!
                                          .toDouble(),
                                      minRating: 1,
                                      direction: Axis.horizontal,
                                      allowHalfRating: true,
                                      itemSize: 15.0,
                                      itemCount: 5,
                                      itemPadding:
                                      EdgeInsets.symmetric(horizontal: 4.0),
                                      itemBuilder: (context, _) =>
                                          Icon(
                                            Icons.star,
                                            color: Colors.amber,
                                          ),
                                      onRatingUpdate: (rating) {
                                        print(rating);
                                      },
                                    ),
                                    Text(products[index]
                                        .ratingCount!
                                        .toDouble()
                                        .toString()),
                                  ],
                                ),
                              ],
                            ),
                          ),
                        ),
                      ),
                    ),
                  ),
                );
              },
            ),
          ),
        ],
      ),
    );
  });
  }

  List<Tab> _tabs(List<CategoryModel> categoryModel) {
    List<Tab> tabs = [];
    for (CategoryModel category in categoryModel) {
      tabs.add(Tab(
        text: category.name,
      ));
    }
    return tabs;
  }

وهذه كامل الملفات , ملف stream_products.dart

import 'dart:async';
import '../../common/api_service.dart';

import '../../pages/contracts/contracts.dart';
import '../../models/Product.dart';
class StreamProductsBloc implements Disposable
{
  List<ProductsModel>? products;

  final StreamController<List<ProductsModel>> _productsController = StreamController<List<ProductsModel>>.broadcast();
  final StreamController<int> _categoryController = StreamController<int>.broadcast();

  Stream<List<ProductsModel>> get productsStream => _productsController.stream;

  StreamSink<int> get fetchProducts => _categoryController.sink;
  Stream<int> get getProductsForCategoriescategory => _categoryController.stream;

  APIService? apiService;

  int categoryID = 0;

  StreamProductsBloc()
  {
    //this.categoryID = categoryID;
    this.products = [];
    apiService = APIService();
    _productsController.add(products!);
    _categoryController.add(this.categoryID);
    _categoryController.stream.listen(_fetchCategoriesFromApi);
  }

  Future<void> _fetchCategoriesFromApi(int category) async {
    this.products = await apiService!.getProductsForCategories(category);
    _productsController.add(this.products!);
  }

  @override
  void dispose(){
    _productsController.close();
    _categoryController.close();
  }
}

و ملف الواجهة ملف products_screen.dart 

import 'package:bistore/providers/auth.dart';
import 'package:bistore/services/wishlist_provider.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_rating_bar/flutter_rating_bar.dart';
import 'package:flutter_staggered_animations/flutter_staggered_animations.dart';
import 'package:provider/provider.dart';
import '../../models/init_model.dart';
import '../../widgets/shimmer/shimmer_grid.dart';
import '../../generated/l10n.dart';
import '../../models/cart_model.dart';
import '../products/single_product.dart';
import '../../models/Product.dart';
import '../../models/category.dart';
import '../../utils/helper_api.dart';
import '../../pages/home/stream_products.dart';

class Products extends StatefulWidget {
  const Products({Key? key}) : super(key: key);

  @override
  _ProductsState createState() => _ProductsState();
}

class _ProductsState extends State<Products>
    with AutomaticKeepAliveClientMixin, TickerProviderStateMixin {
  @override
  bool get wantKeepAlive => true;

  HelperApi helperApi = new HelperApi();
  int currentIndex = 0;
  late TabController _tabController;
  var refreshKey = GlobalKey<RefreshIndicatorState>();

  StreamProductsBloc streamProductsBloc = StreamProductsBloc();

  late List<CategoryModel> productsCategories;

  @override
  void initState() {
    // ignore: todo
    // TODO: implement initState
    super.initState();
    HelperApi().fetchCategories(1);
  }

  @override
  void dispose() {
    // ignore: todo
    // TODO: implement dispose
    super.dispose();
    _tabController.dispose();
    streamProductsBloc.dispose();
  }

  @override
  // ignore: must_call_super
  Widget build(BuildContext context) {
    return FutureBuilder<List<CategoryModel>>(
      future: helperApi.fetchCategories(1),
      builder: (BuildContext context, AsyncSnapshot snapshot) {
        switch (snapshot.connectionState) {
          case ConnectionState.none:
            return Center(
              child: Text('No Connection'),
            );
          case ConnectionState.waiting:
          case ConnectionState.active:
            return Scaffold(
              body: Center(
                child: CircularProgressIndicator(),
              ),
            );
          case ConnectionState.done:
            if (snapshot.hasError) {
              print(snapshot.error);
            } else {
              if (!snapshot.hasData) {
                print('Data Not Found');
              } else {
                this.productsCategories = snapshot.data;
                streamProductsBloc.fetchProducts
                    .add(this.productsCategories[0].id!);
                return _categories(snapshot.data, context);
              }
            }
            break;
        }
        return Container();
      },
    );
  }

  Widget _categories(List<CategoryModel> categoryModel, BuildContext context) {
    _tabController = TabController(
      initialIndex: 0,
      length: categoryModel.length,
      vsync: this,
    );
    return Scaffold(
      appBar: AppBar(
        title: Text(S.of(context).products),
        bottom: TabBar(
          indicatorColor: Color(0XFF117182),
          indicatorWeight: 5,
          controller: _tabController,
          tabs: _tabs(categoryModel),
          isScrollable: true,
          onTap: (int index) {
            streamProductsBloc.fetchProducts
                .add(this.productsCategories[index].id!);
          },
        ),
      ),
      body: Container(
        child: StreamBuilder(
          stream: streamProductsBloc.productsStream,
          builder: (context, AsyncSnapshot<List<ProductsModel>>? snapshot) {
            switch (snapshot!.connectionState) {
              case ConnectionState.none:
                // ignore: todo
                // TODO: Handle this case.
                return Center(
                  child: CircularProgressIndicator(),
                );
              case ConnectionState.waiting:
                // ignore: todo
                // TODO: Handle this case.
                return ShimmerGrid();
              case ConnectionState.done:
              case ConnectionState.active:
                // ignore: todo
                // TODO: Handle this case.
                if (snapshot.hasError) {
                  return Center(
                    child: ShimmerGrid(),
                  );
                } else {
                  if (!snapshot.hasData) {
                    return ShimmerGrid();
                  } else {
                    return _drawProducts(snapshot.data!, context);
                  }
                }
            }
          },
        ),
      ),
    );
  }

  Widget _drawProducts(List<ProductsModel> products, BuildContext context) {
    final cart = Provider.of<Cart>(context, listen: false);
    var initModel = Provider.of<InitModel>(context, listen: false,);
    var auth = Provider.of<AuthProvider>(context, listen: false);
    return Consumer<WishListProvider>(
        builder: (BuildContext context, wishListData, child) {
    return Container(
      padding: EdgeInsets.only(top: 24),
      child: Column(
        children: [
          Flexible(
            child: GridView.builder(
              gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
                  maxCrossAxisExtent: 200,
                  childAspectRatio: 1 / 2,
                  crossAxisSpacing: 20,
                  mainAxisSpacing: 20),
              itemCount: products.length,
              itemBuilder: (context, index) {
                return Card(
                  clipBehavior: Clip.hardEdge,
                  elevation: 0.9,
                  child: AnimationConfiguration.staggeredList(
                    position: index,
                    duration: const Duration(milliseconds: 375),
                    child: SlideAnimation(
                      verticalOffset: 50.0,
                      child: FadeInAnimation(
                        child: Padding(
                          padding: const EdgeInsets.all(8.0),
                          child: InkWell(
                            onTap: () {
                              _gotoSingleProduct(products[index], context);
                            },
                            child: Column(
                              crossAxisAlignment: CrossAxisAlignment.start,
                              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                              children: [
                                Expanded(
                                  // ignore: unnecessary_null_comparison
                                    child: Stack(
                                      children: [
                                        (products[index].images![0].src != null)
                                            ? Image.network(
                                          products[index].images![0].src!,
                                          width:
                                          MediaQuery
                                              .of(context)
                                              .size
                                              .width,
                                          height: MediaQuery
                                              .of(context)
                                              .size
                                              .height,
                                          fit: BoxFit.cover,
                                        )
                                            : Image.asset(
                                          "assets/images/1.jpeg",
                                          width:
                                          MediaQuery
                                              .of(context)
                                              .size
                                              .width,
                                          height: MediaQuery
                                              .of(context)
                                              .size
                                              .height,
                                          fit: BoxFit.fill,
                                        ),
                                        Positioned.directional(
                                          textDirection: Directionality.of(
                                              context),
                                          child: Container(
                                            margin: EdgeInsets.symmetric(
                                                horizontal: 12.0,
                                                vertical: 10.0),
                                            decoration: BoxDecoration(
                                                color: Colors.grey[200],
                                                borderRadius:
                                                BorderRadius.circular(50.0)),
                                            child: IconButton(
                                              icon: Icon(
                                                  Icons.favorite_outline),
                                              onPressed: () {
                                                //wishListData.getCount(products[index].id!, auth.id!);
                                                wishListData.addNewWishList(
                                                    price: products[index]
                                                        .price!
                                                        .toString(),
                                                    product: products[index]
                                                        .name!,
                                                    image: products[index]
                                                        .images![0]
                                                        .src!,
                                                    productId: products[index]
                                                        .id,
                                                    userId: auth.id);
                                                ScaffoldMessenger.of(context)
                                                    .showSnackBar(
                                                  SnackBar(
                                                    content: Text(
                                                      S
                                                          .of(context)
                                                          .add_product_to_wishlist,
                                                    ),
                                                    duration: Duration(
                                                        seconds: 2),
                                                  ),
                                                );
                                              },
                                              iconSize: 20.0,
                                            ),
                                          ),
                                        )
                                      ],
                                    )
                                ),
                                Padding(
                                  padding: const EdgeInsets.all(8.0),
                                  child: Text(
                                    products[index].name!.substring(0, 10),
                                    style: TextStyle(
                                      color: Colors.black,
                                      fontWeight: FontWeight.bold,
                                      fontSize: 18.0,
                                    ),
                                  ),
                                ),
                                Row(
                                  crossAxisAlignment: CrossAxisAlignment.start,
                                  mainAxisAlignment:
                                  MainAxisAlignment.spaceBetween,
                                  children: [
                                    Padding(
                                      padding: const EdgeInsets.all(8.0),
                                      child: Text(initModel.currency! +
                                          products[index].price!,
                                        style: TextStyle(
                                          color: Colors.black,
                                          fontSize: 15.0,
                                        ),
                                      ),
                                    ),
                                    IconButton(
                                      icon: Icon(
                                          Icons.add_shopping_cart_outlined),
                                      onPressed: () {
                                        //if(auth.status == Status.Authenticated){
                                        cart.addItem(
                                            products[index].id.toString(),
                                            10.0,
                                            products[index].name!.toString(),
                                            products[index].images![0].src!,
                                            1,
                                            products[index].id.toString());
                                        ScaffoldMessenger.of(context)
                                            .hideCurrentSnackBar();
                                        ScaffoldMessenger.of(context)
                                            .showSnackBar(
                                          SnackBar(
                                            content: Text(
                                              S
                                                  .of(context)
                                                  .product_added_to_the_cart,
                                            ),
                                            duration: Duration(seconds: 2),
                                            action: SnackBarAction(
                                              label: S
                                                  .of(context)
                                                  .undo,
                                              onPressed: () {
                                                cart.reomveSingleItem(
                                                    products[index]
                                                        .id
                                                        .toString());
                                              },
                                            ),
                                          ),
                                        );
                                      },
                                    ),
                                  ],
                                ),
                                Text(products[index].stockStatus!,
                                  style: TextStyle(
                                    color: Colors.orange,
                                    fontWeight: FontWeight.bold,
                                    fontSize: 15,
                                  ),),
                                Row(
                                  crossAxisAlignment: CrossAxisAlignment.start,
                                  mainAxisAlignment: MainAxisAlignment.start,
                                  children: [
                                    RatingBar.builder(
                                      initialRating: products[index]
                                          .ratingCount!
                                          .toDouble(),
                                      minRating: 1,
                                      direction: Axis.horizontal,
                                      allowHalfRating: true,
                                      itemSize: 15.0,
                                      itemCount: 5,
                                      itemPadding:
                                      EdgeInsets.symmetric(horizontal: 4.0),
                                      itemBuilder: (context, _) =>
                                          Icon(
                                            Icons.star,
                                            color: Colors.amber,
                                          ),
                                      onRatingUpdate: (rating) {
                                        print(rating);
                                      },
                                    ),
                                    Text(products[index]
                                        .ratingCount!
                                        .toDouble()
                                        .toString()),
                                  ],
                                ),
                              ],
                            ),
                          ),
                        ),
                      ),
                    ),
                  ),
                );
              },
            ),
          ),
        ],
      ),
    );
  });
  }

  List<Tab> _tabs(List<CategoryModel> categoryModel) {
    List<Tab> tabs = [];
    for (CategoryModel category in categoryModel) {
      tabs.add(Tab(
        text: category.name,
      ));
    }
    return tabs;
  }

  void _gotoSingleProduct(
      ProductsModel singleProductModel, BuildContext context) {
    Navigator.push(
      context,
      MaterialPageRoute(
          builder: (context) => SingleProduct(singleProductModel)),
    );
  }
}

class ProductsList extends StatelessWidget {
  final List<ProductsModel> productsModel;

  ProductsList({Key? key, required this.productsModel}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Expanded(
          child: ListView.builder(
            scrollDirection: Axis.vertical,
            itemCount: productsModel.length,
            itemBuilder: (context, index) {
              return Text('${productsModel[index].name}');
            },
          ),
        ),
      ],
    );
  }
}

 

  • 0
نشر
بتاريخ منذ ساعة مضت قال بلال زيادة:

هناك طريقة وهي استخدام StreamController بحيث هي طريقة من طرق إدارة الحالة في فلاتر. و الأمر معقد جداً و يجب أن تكون على دراية جيدة بكيفية استخدام StreamController. لاحظ بأنه يجب أن تقوم بتعلم StreamController حتى تفهم الإجابة جيداً لأنه في الوهلة الأولى ستجد أن الأمر قد يكون فيه صعوبة 

يمكنك إنشاء ملف وليكن مسؤول عن التنصت على أي حدث جديد و يعكسه على الواجهة أي يقوم بتنفيذ هذا الحدث على الواجهة و الميزة في ذلك إنها تقوم بتنفيذ الحدث بدون اللجوء إلى بناء نفسها من الصفر و هذا الملف فليكن اسمه StreamProductsBloc.dart ويمكننا تعريف عدة متغيرات في هذا الملف بهذا الشكل 


  List<ProductsModel>? products;

  final StreamController<List<ProductsModel>> _productsController = StreamController<List<ProductsModel>>.broadcast();
  final StreamController<int> _categoryController = StreamController<int>.broadcast();

  Stream<List<ProductsModel>> get productsStream => _productsController.stream;

  StreamSink<int> get fetchProducts => _categoryController.sink;
  Stream<int> get getProductsForCategoriescategory => _categoryController.stream;

  APIService? apiService;

  int categoryID = 0;

List<ProductsModel>? products;

بحيث أول شيء نقوم بتعريف الكلاس مودل الخاص بالمنتجات.


final StreamController<List<ProductsModel>> _productsController = StreamController<List<ProductsModel>>.broadcast();

و من ثم نقوم بتعريف StreamController ليقوم بالتحكم في العملية , ويتم توفير واجهات مختلفة لإنشاء تدفقات أحداث متنوعة.


final StreamController<int> _categoryController = StreamController<int>.broadcast();

وحدة تحكم حيث يمكن الاستماع إليه أكثر من مرة .


Stream<List<ProductsModel>> get productsStream => _productsController.stream;

ثم نقوم بالحصول على البث للمراقبة.


StreamSink<int> get fetchProducts => _categoryController.sink;

ثم نقوم بإدخال حدث إضافي عن طريق StreamSink. 


StreamProductsBloc()
  {
    //this.categoryID = categoryID;
    this.products = [];
    apiService = APIService();
    _productsController.add(products!);
    _categoryController.add(this.categoryID);
    _categoryController.stream.listen(_fetchCategoriesFromApi);
  }

  Future<void> _fetchCategoriesFromApi(int category) async {
    this.products = await apiService!.getProductsForCategories(category);
    _productsController.add(this.products!);
  }

  @override
  void dispose(){
    _productsController.close();
    _categoryController.close();
  }

نقوم بإنشاء دالة جلب بيانات التصنيف عند تمرير id التصنيف و نقوم بإرجاع جميع المنتجات و من ثم نقوم بإضافة هذه البيانات إلى وحدة التحكم.


Future<void> _fetchCategoriesFromApi(int category) async {
    this.products = await apiService!.getProductsForCategories(category);
    _productsController.add(this.products!);
}

 ثم نقوم بإضافة المنتجات و id التصنيف إلى وحدة التحكم في دالة StreamProductsBloc ثم نقوم بمراقبة الحدث عن طريق استخدام listen 


StreamProductsBloc()
  {
    //this.categoryID = categoryID;
    this.products = [];
    apiService = APIService();
    _productsController.add(products!);
    _categoryController.add(this.categoryID);
    _categoryController.stream.listen(_fetchCategoriesFromApi);
  }

ثم نقوم بإنشاء ملف واجهة عرض البيانات وليكن مثلاً باسم products_screen.dart و نقوم أولاً بإنشاء نسخة جديدة من الملف الذي قمنا بإنشائه مسبقاً 


StreamProductsBloc streamProductsBloc = StreamProductsBloc();

ثم ننشأ عدة متغيرات و نعرف TabController لوضع التصنيفات في هذه TabController


bool get wantKeepAlive => true;

HelperApi helperApi = new HelperApi();
int currentIndex = 0;
late TabController _tabController;

ثم نقوم بصنع Widget خاصة بعرض التصنيفات في TabController 


Widget _categories(List<CategoryModel> categoryModel, BuildContext context) {
    _tabController = TabController(
      initialIndex: 0,
      length: categoryModel.length,
      vsync: this,
    );
    return Scaffold(
      appBar: AppBar(
        title: Text(S.of(context).products),
        bottom: TabBar(
          indicatorColor: Color(0XFF117182),
          indicatorWeight: 5,
          controller: _tabController,
          tabs: _tabs(categoryModel),
          isScrollable: true,
          onTap: (int index) {
            streamProductsBloc.fetchProducts
                .add(this.productsCategories[index].id!);
          },
        ),
      ),
      body: Container(
        child: StreamBuilder(
          stream: streamProductsBloc.productsStream,
          builder: (context, AsyncSnapshot<List<ProductsModel>>? snapshot) {
            switch (snapshot!.connectionState) {
              case ConnectionState.none:
                // ignore: todo
                // TODO: Handle this case.
                return Center(
                  child: CircularProgressIndicator(),
                );
              case ConnectionState.waiting:
                // ignore: todo
                // TODO: Handle this case.
                return ShimmerGrid();
              case ConnectionState.done:
              case ConnectionState.active:
                // ignore: todo
                // TODO: Handle this case.
                if (snapshot.hasError) {
                  return Center(
                    child: ShimmerGrid(),
                  );
                } else {
                  if (!snapshot.hasData) {
                    return ShimmerGrid();
                  } else {
                    return _drawProducts(snapshot.data!, context);
                  }
                }
            }
          },
        ),
      ),
    );
  }

لاحظ أننا نقوم بجلب منتجات كل تصنيف عند الضغط عليها عن طريق استخدام id هذا التصنيف 


streamProductsBloc.fetchProducts.add(this.productsCategories[index].id!);

و من ثم نقوم بإضافة هذا الحدث إلى streamProductBloc . 

ثم نقوم برسم Widget الخاص بالمنتجات 


Widget _drawProducts(List<ProductsModel> products, BuildContext context) {
    final cart = Provider.of<Cart>(context, listen: false);
    var initModel = Provider.of<InitModel>(context, listen: false,);
    var auth = Provider.of<AuthProvider>(context, listen: false);
    return Consumer<WishListProvider>(
        builder: (BuildContext context, wishListData, child) {
    return Container(
      padding: EdgeInsets.only(top: 24),
      child: Column(
        children: [
          Flexible(
            child: GridView.builder(
              gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
                  maxCrossAxisExtent: 200,
                  childAspectRatio: 1 / 2,
                  crossAxisSpacing: 20,
                  mainAxisSpacing: 20),
              itemCount: products.length,
              itemBuilder: (context, index) {
                return Card(
                  clipBehavior: Clip.hardEdge,
                  elevation: 0.9,
                  child: AnimationConfiguration.staggeredList(
                    position: index,
                    duration: const Duration(milliseconds: 375),
                    child: SlideAnimation(
                      verticalOffset: 50.0,
                      child: FadeInAnimation(
                        child: Padding(
                          padding: const EdgeInsets.all(8.0),
                          child: InkWell(
                            onTap: () {
                              _gotoSingleProduct(products[index], context);
                            },
                            child: Column(
                              crossAxisAlignment: CrossAxisAlignment.start,
                              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                              children: [
                                Expanded(
                                  // ignore: unnecessary_null_comparison
                                    child: Stack(
                                      children: [
                                        (products[index].images![0].src != null)
                                            ? Image.network(
                                          products[index].images![0].src!,
                                          width:
                                          MediaQuery
                                              .of(context)
                                              .size
                                              .width,
                                          height: MediaQuery
                                              .of(context)
                                              .size
                                              .height,
                                          fit: BoxFit.cover,
                                        )
                                            : Image.asset(
                                          "assets/images/1.jpeg",
                                          width:
                                          MediaQuery
                                              .of(context)
                                              .size
                                              .width,
                                          height: MediaQuery
                                              .of(context)
                                              .size
                                              .height,
                                          fit: BoxFit.fill,
                                        ),
                                        Positioned.directional(
                                          textDirection: Directionality.of(
                                              context),
                                          child: Container(
                                            margin: EdgeInsets.symmetric(
                                                horizontal: 12.0,
                                                vertical: 10.0),
                                            decoration: BoxDecoration(
                                                color: Colors.grey[200],
                                                borderRadius:
                                                BorderRadius.circular(50.0)),
                                            child: IconButton(
                                              icon: Icon(
                                                  Icons.favorite_outline),
                                              onPressed: () {
                                                //wishListData.getCount(products[index].id!, auth.id!);
                                                wishListData.addNewWishList(
                                                    price: products[index]
                                                        .price!
                                                        .toString(),
                                                    product: products[index]
                                                        .name!,
                                                    image: products[index]
                                                        .images![0]
                                                        .src!,
                                                    productId: products[index]
                                                        .id,
                                                    userId: auth.id);
                                                ScaffoldMessenger.of(context)
                                                    .showSnackBar(
                                                  SnackBar(
                                                    content: Text(
                                                      S
                                                          .of(context)
                                                          .add_product_to_wishlist,
                                                    ),
                                                    duration: Duration(
                                                        seconds: 2),
                                                  ),
                                                );
                                              },
                                              iconSize: 20.0,
                                            ),
                                          ),
                                        )
                                      ],
                                    )
                                ),
                                Padding(
                                  padding: const EdgeInsets.all(8.0),
                                  child: Text(
                                    products[index].name!.substring(0, 10),
                                    style: TextStyle(
                                      color: Colors.black,
                                      fontWeight: FontWeight.bold,
                                      fontSize: 18.0,
                                    ),
                                  ),
                                ),
                                Row(
                                  crossAxisAlignment: CrossAxisAlignment.start,
                                  mainAxisAlignment:
                                  MainAxisAlignment.spaceBetween,
                                  children: [
                                    Padding(
                                      padding: const EdgeInsets.all(8.0),
                                      child: Text(initModel.currency! +
                                          products[index].price!,
                                        style: TextStyle(
                                          color: Colors.black,
                                          fontSize: 15.0,
                                        ),
                                      ),
                                    ),
                                    IconButton(
                                      icon: Icon(
                                          Icons.add_shopping_cart_outlined),
                                      onPressed: () {
                                        //if(auth.status == Status.Authenticated){
                                        cart.addItem(
                                            products[index].id.toString(),
                                            10.0,
                                            products[index].name!.toString(),
                                            products[index].images![0].src!,
                                            1,
                                            products[index].id.toString());
                                        ScaffoldMessenger.of(context)
                                            .hideCurrentSnackBar();
                                        ScaffoldMessenger.of(context)
                                            .showSnackBar(
                                          SnackBar(
                                            content: Text(
                                              S
                                                  .of(context)
                                                  .product_added_to_the_cart,
                                            ),
                                            duration: Duration(seconds: 2),
                                            action: SnackBarAction(
                                              label: S
                                                  .of(context)
                                                  .undo,
                                              onPressed: () {
                                                cart.reomveSingleItem(
                                                    products[index]
                                                        .id
                                                        .toString());
                                              },
                                            ),
                                          ),
                                        );
                                      },
                                    ),
                                  ],
                                ),
                                Text(products[index].stockStatus!,
                                  style: TextStyle(
                                    color: Colors.orange,
                                    fontWeight: FontWeight.bold,
                                    fontSize: 15,
                                  ),),
                                Row(
                                  crossAxisAlignment: CrossAxisAlignment.start,
                                  mainAxisAlignment: MainAxisAlignment.start,
                                  children: [
                                    RatingBar.builder(
                                      initialRating: products[index]
                                          .ratingCount!
                                          .toDouble(),
                                      minRating: 1,
                                      direction: Axis.horizontal,
                                      allowHalfRating: true,
                                      itemSize: 15.0,
                                      itemCount: 5,
                                      itemPadding:
                                      EdgeInsets.symmetric(horizontal: 4.0),
                                      itemBuilder: (context, _) =>
                                          Icon(
                                            Icons.star,
                                            color: Colors.amber,
                                          ),
                                      onRatingUpdate: (rating) {
                                        print(rating);
                                      },
                                    ),
                                    Text(products[index]
                                        .ratingCount!
                                        .toDouble()
                                        .toString()),
                                  ],
                                ),
                              ],
                            ),
                          ),
                        ),
                      ),
                    ),
                  ),
                );
              },
            ),
          ),
        ],
      ),
    );
  });
  }

  List<Tab> _tabs(List<CategoryModel> categoryModel) {
    List<Tab> tabs = [];
    for (CategoryModel category in categoryModel) {
      tabs.add(Tab(
        text: category.name,
      ));
    }
    return tabs;
  }

وهذه كامل الملفات , ملف stream_products.dart


import 'dart:async';
import '../../common/api_service.dart';

import '../../pages/contracts/contracts.dart';
import '../../models/Product.dart';
class StreamProductsBloc implements Disposable
{
  List<ProductsModel>? products;

  final StreamController<List<ProductsModel>> _productsController = StreamController<List<ProductsModel>>.broadcast();
  final StreamController<int> _categoryController = StreamController<int>.broadcast();

  Stream<List<ProductsModel>> get productsStream => _productsController.stream;

  StreamSink<int> get fetchProducts => _categoryController.sink;
  Stream<int> get getProductsForCategoriescategory => _categoryController.stream;

  APIService? apiService;

  int categoryID = 0;

  StreamProductsBloc()
  {
    //this.categoryID = categoryID;
    this.products = [];
    apiService = APIService();
    _productsController.add(products!);
    _categoryController.add(this.categoryID);
    _categoryController.stream.listen(_fetchCategoriesFromApi);
  }

  Future<void> _fetchCategoriesFromApi(int category) async {
    this.products = await apiService!.getProductsForCategories(category);
    _productsController.add(this.products!);
  }

  @override
  void dispose(){
    _productsController.close();
    _categoryController.close();
  }
}

و ملف الواجهة ملف products_screen.dart 


import 'package:bistore/providers/auth.dart';
import 'package:bistore/services/wishlist_provider.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_rating_bar/flutter_rating_bar.dart';
import 'package:flutter_staggered_animations/flutter_staggered_animations.dart';
import 'package:provider/provider.dart';
import '../../models/init_model.dart';
import '../../widgets/shimmer/shimmer_grid.dart';
import '../../generated/l10n.dart';
import '../../models/cart_model.dart';
import '../products/single_product.dart';
import '../../models/Product.dart';
import '../../models/category.dart';
import '../../utils/helper_api.dart';
import '../../pages/home/stream_products.dart';

class Products extends StatefulWidget {
  const Products({Key? key}) : super(key: key);

  @override
  _ProductsState createState() => _ProductsState();
}

class _ProductsState extends State<Products>
    with AutomaticKeepAliveClientMixin, TickerProviderStateMixin {
  @override
  bool get wantKeepAlive => true;

  HelperApi helperApi = new HelperApi();
  int currentIndex = 0;
  late TabController _tabController;
  var refreshKey = GlobalKey<RefreshIndicatorState>();

  StreamProductsBloc streamProductsBloc = StreamProductsBloc();

  late List<CategoryModel> productsCategories;

  @override
  void initState() {
    // ignore: todo
    // TODO: implement initState
    super.initState();
    HelperApi().fetchCategories(1);
  }

  @override
  void dispose() {
    // ignore: todo
    // TODO: implement dispose
    super.dispose();
    _tabController.dispose();
    streamProductsBloc.dispose();
  }

  @override
  // ignore: must_call_super
  Widget build(BuildContext context) {
    return FutureBuilder<List<CategoryModel>>(
      future: helperApi.fetchCategories(1),
      builder: (BuildContext context, AsyncSnapshot snapshot) {
        switch (snapshot.connectionState) {
          case ConnectionState.none:
            return Center(
              child: Text('No Connection'),
            );
          case ConnectionState.waiting:
          case ConnectionState.active:
            return Scaffold(
              body: Center(
                child: CircularProgressIndicator(),
              ),
            );
          case ConnectionState.done:
            if (snapshot.hasError) {
              print(snapshot.error);
            } else {
              if (!snapshot.hasData) {
                print('Data Not Found');
              } else {
                this.productsCategories = snapshot.data;
                streamProductsBloc.fetchProducts
                    .add(this.productsCategories[0].id!);
                return _categories(snapshot.data, context);
              }
            }
            break;
        }
        return Container();
      },
    );
  }

  Widget _categories(List<CategoryModel> categoryModel, BuildContext context) {
    _tabController = TabController(
      initialIndex: 0,
      length: categoryModel.length,
      vsync: this,
    );
    return Scaffold(
      appBar: AppBar(
        title: Text(S.of(context).products),
        bottom: TabBar(
          indicatorColor: Color(0XFF117182),
          indicatorWeight: 5,
          controller: _tabController,
          tabs: _tabs(categoryModel),
          isScrollable: true,
          onTap: (int index) {
            streamProductsBloc.fetchProducts
                .add(this.productsCategories[index].id!);
          },
        ),
      ),
      body: Container(
        child: StreamBuilder(
          stream: streamProductsBloc.productsStream,
          builder: (context, AsyncSnapshot<List<ProductsModel>>? snapshot) {
            switch (snapshot!.connectionState) {
              case ConnectionState.none:
                // ignore: todo
                // TODO: Handle this case.
                return Center(
                  child: CircularProgressIndicator(),
                );
              case ConnectionState.waiting:
                // ignore: todo
                // TODO: Handle this case.
                return ShimmerGrid();
              case ConnectionState.done:
              case ConnectionState.active:
                // ignore: todo
                // TODO: Handle this case.
                if (snapshot.hasError) {
                  return Center(
                    child: ShimmerGrid(),
                  );
                } else {
                  if (!snapshot.hasData) {
                    return ShimmerGrid();
                  } else {
                    return _drawProducts(snapshot.data!, context);
                  }
                }
            }
          },
        ),
      ),
    );
  }

  Widget _drawProducts(List<ProductsModel> products, BuildContext context) {
    final cart = Provider.of<Cart>(context, listen: false);
    var initModel = Provider.of<InitModel>(context, listen: false,);
    var auth = Provider.of<AuthProvider>(context, listen: false);
    return Consumer<WishListProvider>(
        builder: (BuildContext context, wishListData, child) {
    return Container(
      padding: EdgeInsets.only(top: 24),
      child: Column(
        children: [
          Flexible(
            child: GridView.builder(
              gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
                  maxCrossAxisExtent: 200,
                  childAspectRatio: 1 / 2,
                  crossAxisSpacing: 20,
                  mainAxisSpacing: 20),
              itemCount: products.length,
              itemBuilder: (context, index) {
                return Card(
                  clipBehavior: Clip.hardEdge,
                  elevation: 0.9,
                  child: AnimationConfiguration.staggeredList(
                    position: index,
                    duration: const Duration(milliseconds: 375),
                    child: SlideAnimation(
                      verticalOffset: 50.0,
                      child: FadeInAnimation(
                        child: Padding(
                          padding: const EdgeInsets.all(8.0),
                          child: InkWell(
                            onTap: () {
                              _gotoSingleProduct(products[index], context);
                            },
                            child: Column(
                              crossAxisAlignment: CrossAxisAlignment.start,
                              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                              children: [
                                Expanded(
                                  // ignore: unnecessary_null_comparison
                                    child: Stack(
                                      children: [
                                        (products[index].images![0].src != null)
                                            ? Image.network(
                                          products[index].images![0].src!,
                                          width:
                                          MediaQuery
                                              .of(context)
                                              .size
                                              .width,
                                          height: MediaQuery
                                              .of(context)
                                              .size
                                              .height,
                                          fit: BoxFit.cover,
                                        )
                                            : Image.asset(
                                          "assets/images/1.jpeg",
                                          width:
                                          MediaQuery
                                              .of(context)
                                              .size
                                              .width,
                                          height: MediaQuery
                                              .of(context)
                                              .size
                                              .height,
                                          fit: BoxFit.fill,
                                        ),
                                        Positioned.directional(
                                          textDirection: Directionality.of(
                                              context),
                                          child: Container(
                                            margin: EdgeInsets.symmetric(
                                                horizontal: 12.0,
                                                vertical: 10.0),
                                            decoration: BoxDecoration(
                                                color: Colors.grey[200],
                                                borderRadius:
                                                BorderRadius.circular(50.0)),
                                            child: IconButton(
                                              icon: Icon(
                                                  Icons.favorite_outline),
                                              onPressed: () {
                                                //wishListData.getCount(products[index].id!, auth.id!);
                                                wishListData.addNewWishList(
                                                    price: products[index]
                                                        .price!
                                                        .toString(),
                                                    product: products[index]
                                                        .name!,
                                                    image: products[index]
                                                        .images![0]
                                                        .src!,
                                                    productId: products[index]
                                                        .id,
                                                    userId: auth.id);
                                                ScaffoldMessenger.of(context)
                                                    .showSnackBar(
                                                  SnackBar(
                                                    content: Text(
                                                      S
                                                          .of(context)
                                                          .add_product_to_wishlist,
                                                    ),
                                                    duration: Duration(
                                                        seconds: 2),
                                                  ),
                                                );
                                              },
                                              iconSize: 20.0,
                                            ),
                                          ),
                                        )
                                      ],
                                    )
                                ),
                                Padding(
                                  padding: const EdgeInsets.all(8.0),
                                  child: Text(
                                    products[index].name!.substring(0, 10),
                                    style: TextStyle(
                                      color: Colors.black,
                                      fontWeight: FontWeight.bold,
                                      fontSize: 18.0,
                                    ),
                                  ),
                                ),
                                Row(
                                  crossAxisAlignment: CrossAxisAlignment.start,
                                  mainAxisAlignment:
                                  MainAxisAlignment.spaceBetween,
                                  children: [
                                    Padding(
                                      padding: const EdgeInsets.all(8.0),
                                      child: Text(initModel.currency! +
                                          products[index].price!,
                                        style: TextStyle(
                                          color: Colors.black,
                                          fontSize: 15.0,
                                        ),
                                      ),
                                    ),
                                    IconButton(
                                      icon: Icon(
                                          Icons.add_shopping_cart_outlined),
                                      onPressed: () {
                                        //if(auth.status == Status.Authenticated){
                                        cart.addItem(
                                            products[index].id.toString(),
                                            10.0,
                                            products[index].name!.toString(),
                                            products[index].images![0].src!,
                                            1,
                                            products[index].id.toString());
                                        ScaffoldMessenger.of(context)
                                            .hideCurrentSnackBar();
                                        ScaffoldMessenger.of(context)
                                            .showSnackBar(
                                          SnackBar(
                                            content: Text(
                                              S
                                                  .of(context)
                                                  .product_added_to_the_cart,
                                            ),
                                            duration: Duration(seconds: 2),
                                            action: SnackBarAction(
                                              label: S
                                                  .of(context)
                                                  .undo,
                                              onPressed: () {
                                                cart.reomveSingleItem(
                                                    products[index]
                                                        .id
                                                        .toString());
                                              },
                                            ),
                                          ),
                                        );
                                      },
                                    ),
                                  ],
                                ),
                                Text(products[index].stockStatus!,
                                  style: TextStyle(
                                    color: Colors.orange,
                                    fontWeight: FontWeight.bold,
                                    fontSize: 15,
                                  ),),
                                Row(
                                  crossAxisAlignment: CrossAxisAlignment.start,
                                  mainAxisAlignment: MainAxisAlignment.start,
                                  children: [
                                    RatingBar.builder(
                                      initialRating: products[index]
                                          .ratingCount!
                                          .toDouble(),
                                      minRating: 1,
                                      direction: Axis.horizontal,
                                      allowHalfRating: true,
                                      itemSize: 15.0,
                                      itemCount: 5,
                                      itemPadding:
                                      EdgeInsets.symmetric(horizontal: 4.0),
                                      itemBuilder: (context, _) =>
                                          Icon(
                                            Icons.star,
                                            color: Colors.amber,
                                          ),
                                      onRatingUpdate: (rating) {
                                        print(rating);
                                      },
                                    ),
                                    Text(products[index]
                                        .ratingCount!
                                        .toDouble()
                                        .toString()),
                                  ],
                                ),
                              ],
                            ),
                          ),
                        ),
                      ),
                    ),
                  ),
                );
              },
            ),
          ),
        ],
      ),
    );
  });
  }

  List<Tab> _tabs(List<CategoryModel> categoryModel) {
    List<Tab> tabs = [];
    for (CategoryModel category in categoryModel) {
      tabs.add(Tab(
        text: category.name,
      ));
    }
    return tabs;
  }

  void _gotoSingleProduct(
      ProductsModel singleProductModel, BuildContext context) {
    Navigator.push(
      context,
      MaterialPageRoute(
          builder: (context) => SingleProduct(singleProductModel)),
    );
  }
}

class ProductsList extends StatelessWidget {
  final List<ProductsModel> productsModel;

  ProductsList({Key? key, required this.productsModel}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Expanded(
          child: ListView.builder(
            scrollDirection: Axis.vertical,
            itemCount: productsModel.length,
            itemBuilder: (context, index) {
              return Text('${productsModel[index].name}');
            },
          ),
        ),
      ],
    );
  }
}

 

شكرا جدا أستاذ بلال، لكن يبدو أن هناك نقص في الملفات بما أنها تحتوي على أكواد كثيرة تعتمد على ملفات أخرى، هل يمكنك إرسال المشروع كامل حتى أستطيع أخذ الفكرة منه

  • 0
نشر
بتاريخ 45 دقائق مضت قال Mohammed Abu Yousef:

شكرا جدا أستاذ بلال، لكن يبدو أن هناك نقص في الملفات بما أنها تحتوي على أكواد كثيرة تعتمد على ملفات أخرى، هل يمكنك إرسال المشروع كامل حتى أستطيع أخذ الفكرة منه

باقي الملفات الموجودة هي ملفات تكميلية للواجهة و لكن يمكنك الاعتماد على الاكواد الخاصة ب tabbar و widget الخاصة بعرض المنتجات.

انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أجب على هذا السؤال...

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.

  • إعلانات

  • تابعنا على



×
×
  • أضف...