How to change the color of an Icon through boolean return in Flutter?

I have a method that queries books that are favored in the Firestore database, the book page has a star icon in black color, I use isfavorite method to query if the open book is favored by the user or not, if it is it should return true and change the icon color to yellow but the change does not happen.

The updateFavorite method works perfectly by adding and removing the favorite book from the bank by tapping the icon, only his color I can't set up.

       InkWell(
          child: Icon(
            Icons.star,
            size: 30,
            color: isFavorite == true ? Colors.yellow
            : Colors.black,
          ),
          onTap: (){

            model.updateFavorite(model.getUserId(), document.documentID);
          },
        ),

==============

Future<bool> isFavorite() async{

            firebaseUser = await _auth.currentUser();

            DocumentSnapshot favoritesRef = await Firestore.instance.collection("users")
                .document(firebaseUser.uid).get();

            if(favoritesRef.data["favorites"].contains(document.documentID)){
              print("SIM");
              return true;
            }
            else {
              print("NÃO");
              return false;
            }

          }

==============

      Future<bool> updateFavorite(Future<DocumentReference> uid, String bookId) async{

        firebaseUser = await _auth.currentUser();

        DocumentReference favoritesRef = Firestore.instance.collection("users")
            .document(firebaseUser.uid);

        return Firestore.instance.runTransaction((Transaction tx) async{

          DocumentSnapshot postSnapshot = await tx.get(favoritesRef);
          if(postSnapshot.exists){

            if(!postSnapshot.data["favorites"].contains(bookId)){
              await tx.update(favoritesRef, <String, dynamic>{
                "favorites": FieldValue.arrayUnion([bookId])

              });
              // Delete de bookId from Favorites
            } else {
              await tx.update(favoritesRef, <String, dynamic>{
                "favorites": FieldValue.arrayRemove([bookId])
              });

            }

          }

        }).then((result){
          print(firebaseUser.uid);
          print(bookId);
          return true;

        }).catchError((error){
          print("Error: $error");
          print("DEU RUIM");
          return false;
        });

      }
Author: djalmafreestyler, 2019-03-31

1 answers

Well, as they have already commented, apparently you are not controlling the state of your application correctly, so after executing your method updateFavorite() you are not warning Flutter that it should render your Icon again.

I noticed that you use 2 Futures, 1 to update the favorite, and another on the icon to actually check whether or not it is a favorite to render the color. In this case you can also use a FutureBuilder , widget well bacaninha which always updates when Future has its result. I created an example for you to have idea of the operation and adapt for its use.

Main.dart

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

  YourBusiness yourBusiness = new YourBusiness();

  @override
  Widget build(BuildContext context) {
    return SafeArea(
        child: Scaffold(
          body: Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Column(
                crossAxisAlignment: CrossAxisAlignment.center,
                mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                children: <Widget>[
                  FutureBuilder(
                    future: yourBusiness.isFavorite(''),
                    builder: (BuildContext context, AsyncSnapshot<bool> snapshot) {
                      bool isFavorite = false;
                      if(snapshot.hasData) { // Verificar se o Future possui dado
                        isFavorite = snapshot.data;
                      }

                      return Icon(Icons.ac_unit,
                        size: 160.0,
                        color: isFavorite ? Colors.greenAccent: Colors.black,
                      );
                    }
                  ),
                  RaisedButton(
                    child: Text('CHANGE COLOR'),
                    onPressed: () {
                      yourBusiness.updateFavorite('').then((bool) {
                        setState(() {});
                      });
                    },
                  ),
                  RaisedButton(
                    child: Text('SET STATE'),
                    onPressed: () {
                      setState(() {});
                    },
                  )
                ],
              )
            ],
          ),
        )
    );
  }
}

Your_business.dart

class YourBusiness {

  bool _isFavorite = false;

  Future<bool> isFavorite(String yourParams) async {
    await Future.delayed(Duration(seconds: 1));

    // DO YOUR STUFF HERE

    return _isFavorite;
  }

  Future<bool> updateFavorite(String yourParams) async {
    await Future.delayed(Duration(seconds: 1));

    // DO YOUR STUFF HERE

    _isFavorite = true;
    return _isFavorite;
  }

}

Result

Result

Keep in mind that every time you update the state of this Widget, the Future of the Icon will run again, which is not a good idea, but you can define other strategies, then it goes from Logic that you want to assemble in your App.

I recommend using some pattern for application state control, such as Bloc.

 2
Author: Julio Henrique Bitencourt, 2019-04-02 13:13:03