0

I am building an online bottle store app using flutter and I am having an issue where if I add a product to favorites the selected product's button won't stay selected on the home page if I switch pages. I have categorized the products using a Tabbar and Tabbarview. I have tried using AutomaticKeepAliveClientMxin to keep the page alive but with no success. Please can anyone assist.

Here's what happens: I click on the selected product enter image description here

then it is added to Favorites enter image description here

Come back to the home page and the selected item is no longer showing that it is selected enter image description here

Here's my code:

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

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage>
    with AutomaticKeepAliveClientMixin, TickerProviderStateMixin {
  ProductProvider productProvider = ProductProvider();
  late TabController tabController;

  @override
  void initState() {
    super.initState();
    tabController = TabController(length: 4, vsync: this);
  }

  @override
  void dispose() {
    tabController.dispose();
    super.dispose();
  }

  @override
  bool get wantKeepAlive => true;

  @override
  Widget build(BuildContext context) {
    super.build(context);
    var cart = Provider.of<ShoppingCartProvider>(context);
    var favoriteProvider = Provider.of<FavoriteProvider>(context);
    Size _screenSize = MediaQuery.of(context).size;
    final double itemHeight = (_screenSize.height - kToolbarHeight - 24) / 2;
    final double itemWidth = _screenSize.width / 2;
    return Scaffold(
      body: SingleChildScrollView(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.start,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            const Padding(
              padding: EdgeInsets.all(8.0),
              child: Text(
                'Categories',
                style: TextStyle(
                    fontSize: 20.0,
                    fontFamily: 'Montserrat-ExtraBold',
                    fontWeight: FontWeight.bold),
              ),
            ),
            Container(
              child: Align(
                alignment: Alignment.centerLeft,
                child: TabBar(
                  controller: tabController,
                  indicator:
                      CircleTabIndicator(color: Colors.redAccent, radius: 4.0),
                  isScrollable: true,
                  labelColor: Colors.redAccent,
                  labelStyle: const TextStyle(
                      fontWeight: FontWeight.bold, fontSize: 20.0),
                  unselectedLabelColor: Colors.black,
                  unselectedLabelStyle: const TextStyle(
                      fontWeight: FontWeight.bold, fontSize: 20.0),
                  tabs: const [
                    Tab(text: 'Brandy'),
                    Tab(text: 'Gin'),
                    Tab(text: 'Soft drinks'),
                    Tab(text: 'Whiskey')
                  ],
                ),
              ),
            ),
            Container(
              height: 400,
              width: double.maxFinite,
              child: TabBarView(
                  controller: tabController,
                  children: productProvider.categories.map((bottleCategory) {
                    return GridView.builder(
                      gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                        crossAxisCount: 2,
                        childAspectRatio: itemWidth / itemHeight,
                      ),
                      itemCount: bottleCategory.bottleList.length,
                      itemBuilder: (context, index) {
                        return Card(
                          shadowColor: Colors.grey,
                          surfaceTintColor: Colors.amber,
                          shape: RoundedRectangleBorder(
                              borderRadius: BorderRadius.circular(20)),
                          child: Stack(
                            children: [
                              Positioned(
                                right: 0,
                                child: InkWell(
                                  onTap: () {
                                    favoriteProvider.toggleFavorites(
                                        bottleCategory.bottleList[index]);
                                    if (favoriteProvider.isExist(
                                        bottleCategory.bottleList[index])) {
                                      ScaffoldMessenger.of(context)
                                          .hideCurrentSnackBar();
                                      ScaffoldMessenger.of(context)
                                          .showSnackBar(
                                        const SnackBar(
                                          content: Text(
                                            "Product Added to Favorite!",
                                            style: TextStyle(fontSize: 16),
                                          ),
                                          backgroundColor: Colors.green,
                                          duration: Duration(seconds: 1),
                                        ),
                                      );
                                    } else {
                                      ScaffoldMessenger.of(context)
                                          .hideCurrentSnackBar();
                                      ScaffoldMessenger.of(context)
                                          .showSnackBar(
                                        const SnackBar(
                                          content: Text(
                                            "Product Removed from Favorite!",
                                            style: TextStyle(fontSize: 16),
                                          ),
                                          backgroundColor: Colors.red,
                                          duration: Duration(seconds: 1),
                                        ),
                                      );
                                    }
                                  },
                                  child: favoriteProvider.isExist(
                                          bottleCategory.bottleList[index])
                                      ? const Icon(
                                          Icons.favorite,
                                          color: Colors.redAccent,
                                        )
                                      : const Icon(Icons.favorite_border),
                                ),
                              ),
                              Column(
                                mainAxisAlignment: MainAxisAlignment.center,
                                children: [
                                  Center(
                                    child: Image.asset(
                                      bottleCategory.bottleList[index].image,
                                      height: 200.0,
                                    ),
                                  ),
                                  Center(
                                      child: Text(
                                          bottleCategory
                                              .bottleList[index].bottleName,
                                          style: const TextStyle(
                                              fontSize: 20.0,
                                              fontWeight: FontWeight.bold))),
                                  Center(
                                    child: Text(
                                        'R${bottleCategory.bottleList[index].price}'),
                                  )
                                ],
                              ),
                              Positioned(
                                  bottom: 0,
                                  right: 10,
                                  child: IconButton(
                                    icon: const Icon(Icons.add_circle),
                                    iconSize: 40.0,
                                    onPressed: () {
                                      cart.addToCart(
                                          bottleCategory.bottleList[index].id,
                                          bottleCategory
                                              .bottleList[index].bottleName,
                                          bottleCategory
                                              .bottleList[index].price,
                                          bottleCategory
                                              .bottleList[index].image);
                                    },
                                  ))
                            ],
                          ),
                        );
                      },
                    );
                  }).toList()),
            ),
          ],
        ),
      ),
    );
  }
}

class FavoriteProvider with ChangeNotifier {
  List<Bottle> _favItems = [];
  List<Bottle> get favItems {
    return [..._favItems];
  }

  void toggleFavorites(Bottle favBottle) {
    final isExist = _favItems.contains(favBottle);
    if (isExist) {
      _favItems.remove(favBottle);
    } else {
      _favItems.add(favBottle);
    }
    notifyListeners();
  }

  bool isExist(Bottle favBottle) {
    final isExist = _favItems.contains(favBottle);
    return isExist;
  }

  void clearFavorite() {
    _favItems = [];
    notifyListeners();
  }
}
Anesu Mazvimavi
  • 131
  • 1
  • 9

1 Answers1

0

Try using Consumer widget. Like so:

  Consumer<favoriteProvider>(
        builder: (BuildContext context, favorite, _){
          return Icon(
            Icons.favorite,
            color: favorite.isExist(bottleCategory.bottleList[index])? Colors.redAccent : null,
          );
        },
      ),

Consumer widget will refresh or change the state whenever the ChangeNotifier of that model, in this case, FavoriteProvider is triggered, this should allows your widget to change and check itself anytime. So you shouldn't need to keep your state or screen alive all the time.

If that doesn't work, please change your Business Logic in the FavoriteProvider. Instead of using contains, I suggest to use any and identifies each instances with its own id or any of its unique variable. Like so:

  bool isExist(Bottle favBottle) {
    final isExist = _favItems.any((e) =>e.bottleName == favBottle.bottleName);
    return isExist;
  }
IcyHerrscher
  • 391
  • 3
  • 9
  • If I am not mistaken, based on your code I must replace that Widget child code with a consumer is that correct? – Anesu Mazvimavi Sep 13 '22 at 15:40
  • I have tried it and unfortunately it doesn't work. It's still the same end result. It selects and then when I switch pages and come back it becomes unselected. After doing a bit of research I know the problem is usually with Tabbar items it leaves items unselected after switching pages – Anesu Mazvimavi Sep 13 '22 at 18:16
  • Your problem is a bit hard to reproduce since I'm testing on a mobile app, but nevertheless, I have edited my answer, please check it. And do tell if it works or not. – IcyHerrscher Sep 14 '22 at 04:25
  • It worked! Thank you very very much. You truly are a lifesaver. Now I know I shouldn't use contains next time :) – Anesu Mazvimavi Sep 14 '22 at 09:32
  • The only problem I'm now facing is if I add a product to favorites, I can only remove it in Favorites and not home page. In Home page it stays selected, I can't unselect the item for some strange reason. – Anesu Mazvimavi Sep 14 '22 at 12:19
  • No need to worry I finally fixed it. The mistake I made was I was not using the ProductProvider class as an actual provider. I just create an instance and called the class's constructor and that was it. So when I tried removing from the homepage it actually wasn't removing from a list because the list we were supposed to be removing from is in the provider class :) – Anesu Mazvimavi Sep 14 '22 at 15:34
  • Glad you fixed it. I'm sorry I wasn't active at the time to see your message. – IcyHerrscher Feb 04 '23 at 03:05