Search code examples
listflutterclasslistviewlanguagetool

Flutter - list inside a list builder


I don't have much experience with flutter.

I would like to use the language_tool library for Dart and Flutter.

I created the script below:

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

class mainApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Chat(),
    );
  }
}

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

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

class _ChatState extends State<Chat> {
  String text = 'Henlo i am Gabriele';

  Future<List<WritingMistake>> tool(String text) async {
    var tool = LanguageTool();
    var result = tool.check(text);
    var correction = await result;

    print(correction);

    List<WritingMistake> mistakes = [];

    for (var m in correction) {
      //var mistake = m.issueDescription;

      WritingMistake mistake = WritingMistake(
        message: m.message,
        offset: m.offset,
        length: m.length,
        issueType: m.issueType,
        issueDescription: m.issueDescription,
        replacements: m.replacements,
      );

      mistakes.add(mistake);
    }

    print(mistakes.length);
    print(mistakes);

    return mistakes;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Container(
              color: Colors.red,
              height: 150.0,
              width: double.infinity,
              child:
                  Center(child: Text(text, style: TextStyle(fontSize: 20.0))),
            ),
            Text(
              '\n     Tap on the blue button to replace it in the message.\n',
            ),
            FutureBuilder(
              future: tool(text),
              builder: (BuildContext context, AsyncSnapshot snapshot) {
                if (snapshot.data == null) {
                  return Container(
                    child: Center(
                      child: Text('Loading...'),
                    ),
                  );
                } else {
                  return SizedBox(
                    height: 200.0,
                    child: ListView.builder(
                      itemCount: snapshot.data.length,
                      itemBuilder: (BuildContext context, int index) {
                        return Container(
                          child: Padding(
                            padding: const EdgeInsets.all(8.0),
                            child: Column(
                              children: [
                                Row(
                                  children: [
                                    Row(
                                      crossAxisAlignment:
                                          CrossAxisAlignment.start,
                                      children: [
                                        Text('   ' +
                                            (index + 1).toString() +
                                            ' '),
                                        Container(
                                          child: Padding(
                                            padding: const EdgeInsets.all(8.0),
                                            child: Text(text.substring(
                                                snapshot.data[index].offset,
                                                snapshot.data[index].offset +
                                                    snapshot
                                                        .data[index].length)),
                                          ),
                                          color: Colors.blue,
                                        ),
                                      ],
                                    ),
                                    Icon(
                                      Icons.arrow_forward,
                                    ),
                                    Text(snapshot.data[index].issueDescription)
                                  ],
                                ),

                                // Todo: Row with List of .replacements
                              ],
                            ),
                          ),
                          // snapshot.data[index].issueDescription),
                        );
                      },
                    ),
                  );
                }
              },
            ),
            Expanded(child: Container(color: Colors.grey))
          ],
        ),
      ),
    );
  }
}

And it currently looks like this:

enter image description here

And I would like it to become like in this screen, but I would like the green containers derive from the WritingMistake.replacements list (with each element of the list as text):

enter image description here

Do you know how I can do it?


Solution

  • Spent several hours doing exactly what you wanted. My Code:

    import 'dart:async';
    import 'package:flutter/material.dart';
    import 'package:language_tool/language_tool.dart';
    
    void main() => runApp(mainApp());
    
    class mainApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return const MaterialApp(
          home: Chat(),
        );
      }
    }
    
    class Chat extends StatefulWidget {
      const Chat({Key? key}) : super(key: key);
    
      @override
      _ChatState createState() => _ChatState();
    }
    
    class _ChatState extends State<Chat> {
      String text = 'Henlo i am Gabriele';
    
      static List<WritingMistake> mistakes = []; // Moved Here And Init Like Static
    
      Future<List<WritingMistake>> tool(String text) async {
        var tool = LanguageTool();
        var result = tool.check(text);
        var correction = await result;
    
        print(correction);
    
        for (var m in correction) {
          //var mistake = m.issueDescription;
    
          WritingMistake mistake = WritingMistake(
            message: m.message,
            offset: m.offset,
            length: m.length,
            issueType: m.issueType,
            issueDescription: m.issueDescription,
            replacements: m.replacements,
          );
    
          mistakes.add(mistake);
        }
    
        print(mistakes.length);
        print(mistakes);
    
        return mistakes;
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: SafeArea(
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Container(
                  color: Colors.red,
                  height: 150.0,
                  width: double.infinity,
                  child: Center(
                      child: Text(text, style: const TextStyle(fontSize: 20.0))),
                ),
                const Text(
                  '\n     Tap on the blue button to replace it in the message.\n',
                ),
                FutureBuilder(
                  future: tool(text),
                  builder: (BuildContext context, AsyncSnapshot snapshot) {
                    if (snapshot.data == null) {
                      return const Center(
                        child: Text('Loading...'),
                      );
                    } else {
                      return SizedBox(
                        height: 200.0,
                        child: ListView.builder(
                          itemCount: snapshot.data.length,
                          itemBuilder: (BuildContext context, int mistakeIdIndex) {
                            return Container(
                              child: Padding(
                                padding: const EdgeInsets.all(8.0),
                                child: Column(
                                  children: [
                                    Row(
                                      children: [
                                        Row(
                                          crossAxisAlignment:
                                              CrossAxisAlignment.start,
                                          children: [
                                            Text('   ' +
                                                (mistakeIdIndex + 1).toString() +
                                                ' '),
                                            Container(
                                              child: Padding(
                                                padding: const EdgeInsets.all(8.0),
                                                child: Text(text.substring(
                                                    snapshot.data[mistakeIdIndex]
                                                        .offset,
                                                    snapshot.data[mistakeIdIndex]
                                                            .offset +
                                                        snapshot
                                                            .data[mistakeIdIndex]
                                                            .length)),
                                              ),
                                              color: Colors.blue,
                                            ),
                                          ],
                                        ),
                                        const Icon(
                                          Icons.arrow_forward,
                                        ),
                                        Text(snapshot
                                            .data[mistakeIdIndex].issueDescription)
                                      ],
                                    ),
    
                                    // Todo: Row with List of .replacements
                                    SizedBox(
                                      width: MediaQuery.of(context)
                                          .size
                                          .width, // Width = Screen Width
                                      height: 44,
                                      child: ListView.builder(
                                          itemCount: mistakes.length,
                                          scrollDirection: Axis.horizontal,
                                          shrinkWrap: true,
                                          itemBuilder: (BuildContext context,
                                              int replacementsListIndex) {
                                            return buildReplacements(mistakeIdIndex,
                                                replacementsListIndex);
                                          }),
                                    )
                                  ],
                                ),
                              ),
                              // snapshot.data[index].issueDescription),
                            );
                          },
                        ),
                      );
                    }
                  },
                ),
                Expanded(child: Container(color: Colors.grey))
              ],
            ),
          ),
        );
      }
    
      Widget buildReplacements(int mistakeIdIndex, int replacementsListIndex) {
        if (mistakes[replacementsListIndex].replacements!.length == null) {
          return const SizedBox(); // Return Empty If No Replacements Found, Just To Be Safe
        }
    
        // Check For Mistake ID - Remove This Will Cause A Problem with Displaying All Replacements Under All Words
        if (mistakeIdIndex == replacementsListIndex) {
          // If Only 1 Replacement, No Need To Create ListView.builder
          if (mistakes[replacementsListIndex].replacements!.length == 1) {
            return Container(
              margin: const EdgeInsets.all(4),
              padding: const EdgeInsets.all(8),
              decoration: const BoxDecoration(
                  color: Color.fromARGB(255, 174, 213, 130)), // Green Color
              child: Text(
                mistakes[replacementsListIndex].replacements!.toString(),
                style: const TextStyle(),
                textAlign: TextAlign.center,
              ),
            );
          } 
          // Create ListView.builder to Create A Split Between Replacements To One Wrong-Word (Every Replacement Has It's Own Container With Green Background)
          else {
            return ListView.builder(
                itemCount: mistakes[replacementsListIndex].replacements!.length,
                scrollDirection: Axis.horizontal,
                shrinkWrap: true,
                itemBuilder: (context, index) {
                  return Container(
                    margin: const EdgeInsets.all(4),
                    padding: const EdgeInsets.all(8),
                    decoration: const BoxDecoration(
                        color: Color.fromARGB(255, 174, 213, 130)), // Green Color
                    child: Text(
                      mistakes[replacementsListIndex]
                          .replacements![index]!
                          .toString(),
                      style: const TextStyle(),
                      textAlign: TextAlign.center,
                    ),
                  );
                });
          }
        } 
        // If Replacement Not For This Wrong-Word, Then Skip
        else {
          return const SizedBox();
        }
      }
    }
    

    And Screenshot:

    enter image description here