Home > Blockchain >  How do I use setState on a bool of which the initial value isn't know until after the widget bu
How do I use setState on a bool of which the initial value isn't know until after the widget bu

Time:03-26

For a post and comments system, I have a Response class where the status field determines if the response is 'published' or 'hidden'.

I use a FirestoreListView to display these responses. If a response has its status set to hidden, it should be collapsed else it should just show. For this, I have a bool responseVisible. When the responses are first read, I initialize responseVisible as follows:

bool responseVisible = response.status == 'published';

Then I use 2 Visibility widgets. The normal one is visible when responseVisible is true and the collapsed version is visible when responseVisible is false.

This works perfectly. Responses with status published are shown and those with status hidden have a response collapsed message.

But now I want to add a button to open collapsed responses. For this, I use setState to change responseVisible to true. But since I am initializing responseVisible in the widget build method, the setState value keeps being overwritten by the initialization value.

Normally, I would just take the responseVisible bool out of the widget build method and initialize it there but in this case, I can't because the response's status isn't known to me before the widget build method runs.

So now I'm stuck. How can I rewrite this to make opening a collapsed response work?

class Response {
  final String postId;
  final String? responseId;
  final UserProfile author;
  final String content;
  final DateTime datePublished;
  DateTime? dateModified;
  final Map<String, Reply>? replies;
  final String status;
  final String statusContext;

  Response({
    required this.postId,
    this.responseId,
    required this.author,
    required this.content,
    required this.datePublished,
    this.dateModified,
    this.replies,
    required this.status,
    required this.statusContext,
  });
class ResponseStream extends StatefulWidget {
  ResponseStream({Key? key, required this.post, this.height}) : super(key: key);

  final Post post;
  double? height = 400;

  @override
  State<ResponseStream> createState() => _ResponseStreamState();
}

class _ResponseStreamState extends State<ResponseStream> {

  @override
  Widget build(BuildContext context) {
    final responsesCollection = FirebaseFirestore.instance
        .collection('posts')
        .doc(widget.post.postId)
        .collection('responses')
        .orderBy('datePublished', descending: true)
        .withConverter<Response>(
          fromFirestore: (snapshot, _) => Response.fromJson(snapshot.id, snapshot.data()!),
          toFirestore: (responses, _) => responses.toJson(),
        );

    return SizedBox(
      height: widget.height,
      child: FirestoreListView<Response>(
          query: responsesCollection,
          itemBuilder: (context, snapshot) {
            Response response = snapshot.data();
            bool responseVisible = response.status == 'published';

            return ListTile(
              title: Text(
                "${response.author.name} ~ ${fs.format(response.datePublished)}",
              ),
              subtitle: Column(
                children: [
                  Visibility(
                    visible: responseVisible,
                    child: Text(response.content),
                  ),
                  Visibility(
                    visible: !responseVisible,
                    child: Column(
                      children: [
                        Text('This response was collapsed for: ${response.statusContext}.'),
                        GestureDetector(
                          child: const Text("Show Response"),
                          onTap: () {
                            setState(() {
                              responseVisible = !responseVisible;
                            });
                          },
                        ),
                      ],
                    ),
                  ),
                ],
              ),
            );
          }),
    );
  }
}

CodePudding user response:

Have you thought about adding the parameter "responseVisible" to the Response class itself, setting its initial value to false, and then modifying it?

CodePudding user response:

You can create a Map at the top of your ResponseStream Widget to overwrite the existing published values, where the postId maps to the visibility.

Map<String,bool> responseVisibility = new Map();

Set the stored visibilities to the default value if the map does not contain that postId and simply just query the Map.

if(!responseVisibility.containsKey(response.postId)) responseVisibility[response.postId] = response.status == 'published';

bool responseVisible = responseVisibility[response.postId];

Finally, to update the visibility, just update the Map.

setState(() {
  responseVisibility[response.postId] = !responseVisibility[response.postId];
});
  • Related