Как я могу отобразить снимок QueryDocumentSnapshot из Firebase в проекте Flutter? (Флаттер, Firebase, Json, Дарт)

# #json #firebase #flutter #dart

Вопрос:

Ниже приведен пример QueryDocumentSnapshot под названием «неделя», который я получаю из Firestore с помощью StreamBuilder. Я ищу способ отображения этих более или менее сложных данных в чем-то вроде виджета-карты с информацией из каждого снимка в моем проекте Flutter.

 {
    "days":{
        "3": {
            "activities": {
                "1628658343103": {
                    "query": "I am watering the plants", 
                    "finished": false, 
                    "params": [
                        {
                            "pronounsDefinite": "I"
                        }, 
                        {
                            "verbsHelpPresent": "am"
                        },
                        {
                            "verbsGerund": "watering"
                        }, 
                        {
                            "articles": "the"
                        }, 
                        {
                            "nouns": "plant"
                        }
                    ], 
                    "intent": "gHomesAndBuildingsGardensAC", 
                    "duration": 3
                }, 
                "1628673512954": {
                    "query": "I am cutting the bushes", 
                    "finished": false, 
                    "params": [
                        {
                            "pronounsDefinite": "I"
                        }, 
                        {
                            "verbsHelpPresent": "am"
                        }, 
                        {
                            "verbsGerund": "cutting"
                        }, 
                        {
                            "articles": "the"
                        }, 
                        {
                            "nouns": "bush"
                        }
                    ], 
                    "intent": "gHomesAndBuildingsGardensAC", 
                    "duration": 3
                }, 
                "1628673476549": {
                    "query": "I work in the garden", 
                    "finished": false, 
                    "params": [
                        {
                            "pronounsDefinite": "I"
                        }, 
                        {
                            "verbsInfinitiv": "work"
                        }, 
                        {
                            "prepositions": "in"
                        }, 
                        {
                            "articles": "the"
                        }, 
                        {
                            "nouns": "garden"
                        }], 
                    "intent": "gHomesAndBuildingsGardensAC", 
                    "duration": 4
                }
            }
        },
        "4": {
            "activities": {
                "1628658343104": {
                    "query": "I am watering the plants", 
                    "finished": false, 
                    "params": [
                        {
                            "pronounsDefinite": "I"
                        }, 
                        {
                            "verbsHelpPresent": "am"
                        },
                        {
                            "verbsGerund": "watering"
                        }, 
                        {
                            "articles": "the"
                        }, 
                        {
                            "nouns": "plant"
                        }
                    ], 
                    "intent": "gHomesAndBuildingsGardensAC", 
                    "duration": 3
                }, 
                "1628673512956": {
                    "query": "I am cutting the bushes", 
                    "finished": false, 
                    "params": [
                        {
                            "pronounsDefinite": "I"
                        }, 
                        {
                            "verbsHelpPresent": "am"
                        }, 
                        {
                            "verbsGerund": "cutting"
                        }, 
                        {
                            "articles": "the"
                        }, 
                        {
                            "nouns": "bush"
                        }
                    ], 
                    "intent": "gHomesAndBuildingsGardensAC", 
                    "duration": 3
                }, 
                "1628673476559": {
                    "query": "I work in the garden", 
                    "finished": false, 
                    "params": [
                        {
                            "pronounsDefinite": "I"
                        }, 
                        {
                            "verbsInfinitiv": "work"
                        }, 
                        {
                            "prepositions": "in"
                        }, 
                        {
                            "articles": "the"
                        }, 
                        {
                            "nouns": "garden"
                        }], 
                    "intent": "gHomesAndBuildingsGardensAC", 
                    "duration": 3
                }
            }
        }
    }
}

 

Вот в чем проблема:
У меня есть метод ListView.builder, который создает виджет для каждого документа моментального снимка, как описано выше.

Цифровые клавиши в разделе «действия» являются метками времени. Я могу отобразить некоторый текст, используя это:

 ...
Text(
  week['days']['3']['activities']['1628658343103']['query'].toString()
), //Which displays: "I am watering the plants"

 

Но таким образом, я должен был бы знать каждую метку времени и называть ее таким образом с точным номером, который, очевидно, не работает.

Как я могу использовать что-то вроде «forEach ()» для перебора всех существующих записей в действиях?

Я также создал класс модели для этого, используя https://app.quicktype.io но затем он создает исключение FormatException, потому что я пытаюсь вставить в класс QueryDocumentSnapshot в тот момент, когда я пытаюсь это сделать:

 Widget buildCard(BuildContext context, DocumentSnapshot week) {
    final dataFromWeek = dataFromWeekFromJson(week.toString());
    return new Container(.....); 

    //In this Container, all the text from json should be displayed
}

 

а вот мой класс модели, который я получил из инструмента быстрого ввода JSON.

 // To parse this JSON data, do
//
//     final dataFromWeek = dataFromWeekFromJson(jsonString);

import 'dart:convert';

DataFromWeek dataFromWeekFromJson(String str) =>
    DataFromWeek.fromJson(json.decode(str));

String dataFromWeekToJson(DataFromWeek data) => json.encode(data.toJson());

class DataFromWeek {
  DataFromWeek({
    this.days,
  });

  Map<String, Day> days;

  factory DataFromWeek.fromJson(Map<String, dynamic> json) => DataFromWeek(
        days: Map.from(json["days"])
            .map((k, v) => MapEntry<String, Day>(k, Day.fromJson(v))),
      );

  Map<String, dynamic> toJson() => {
        "days": Map.from(days)
            .map((k, v) => MapEntry<String, dynamic>(k, v.toJson())),
      };
}

class Day {
  Day({
    this.activities,
  });

  Map<String, Activity> activities;

  factory Day.fromJson(Map<String, dynamic> json) => Day(
        activities: Map.from(json["activities"])
            .map((k, v) => MapEntry<String, Activity>(k, Activity.fromJson(v))),
      );

  Map<String, dynamic> toJson() => {
        "activities": Map.from(activities)
            .map((k, v) => MapEntry<String, dynamic>(k, v.toJson())),
      };
}

class Activity {
  Activity({
    this.query,
    this.finished,
    this.params,
    this.intent,
    this.duration,
  });

  String query;
  bool finished;
  List<Param> params;
  String intent;
  int duration;

  factory Activity.fromJson(Map<String, dynamic> json) => Activity(
        query: json["query"],
        finished: json["finished"],
        params: List<Param>.from(json["params"].map((x) => Param.fromJson(x))),
        intent: json["intent"],
        duration: json["duration"],
      );

  Map<String, dynamic> toJson() => {
        "query": query,
        "finished": finished,
        "params": List<dynamic>.from(params.map((x) => x.toJson())),
        "intent": intent,
        "duration": duration,
      };
}

class Param {
  Param({
    this.pronounsDefinite,
    this.verbsHelpPresent,
    this.verbsGerund,
    this.articles,
    this.nouns,
    this.verbsInfinitiv,
    this.prepositions,
  });

  String pronounsDefinite;
  String verbsHelpPresent;
  String verbsGerund;
  String articles;
  String nouns;
  String verbsInfinitiv;
  String prepositions;

  factory Param.fromJson(Map<String, dynamic> json) => Param(
        pronounsDefinite:
            json["pronounsDefinite"] == null ? null : json["pronounsDefinite"],
        verbsHelpPresent:
            json["verbsHelpPresent"] == null ? null : json["verbsHelpPresent"],
        verbsGerund: json["verbsGerund"] == null ? null : json["verbsGerund"],
        articles: json["articles"] == null ? null : json["articles"],
        nouns: json["nouns"] == null ? null : json["nouns"],
        verbsInfinitiv:
            json["verbsInfinitiv"] == null ? null : json["verbsInfinitiv"],
        prepositions:
            json["prepositions"] == null ? null : json["prepositions"],
      );

  Map<String, dynamic> toJson() => {
        "pronounsDefinite": pronounsDefinite == null ? null : pronounsDefinite,
        "verbsHelpPresent": verbsHelpPresent == null ? null : verbsHelpPresent,
        "verbsGerund": verbsGerund == null ? null : verbsGerund,
        "articles": articles == null ? null : articles,
        "nouns": nouns == null ? null : nouns,
        "verbsInfinitiv": verbsInfinitiv == null ? null : verbsInfinitiv,
        "prepositions": prepositions == null ? null : prepositions,
      };
}

 

На самом деле я не хочу отображать «параметры», но было бы здорово, если бы была некоторая гибкость, поэтому я пытаюсь использовать класс модели для отображения данных моментального снимка в «Карточке-виджете».

Ответ №1:

Вы хотите получить все действия за определенный день, а затем просмотреть их и создать карточку.

Во-первых, это то, как вы должны структурировать свои данные.

«дни» (коллекция) -> «3» (документ) ->> «мероприятия» (вложенная коллекция в документе 3)

 @override
Widget build(BuildContext context) {
  return Scaffold(
    body: StreamBuilder<QuerySnapshot<Activity>>(
      // below will return all the activities for under doc('3')
      stream: FirebaseFirestore.instance
          .collection("days")
          .doc('3')
          .collection("activities")
          // NB: I used your Activity Model
          .withConverter<Activity>(
            fromFirestore: (snapshot, _) =>
                Activity.fromJson(snapshot.data()),
            toFirestore: (data, _) => data.toJson(),
          )
          .snapshots(),
      builder: (BuildContext context,
          AsyncSnapshot<QuerySnapshot<Activity>> snapshot) {
        if (snapshot.hasError) return Text('Something went wrong');
        if (snapshot.connectionState == ConnectionState.waiting)
          return CircularProgressIndicator();

        // you can then loop through query and build the card;
        List<Activity> _activities =
            snapshot.data.docs.map((e) => e.data()).toList();
        return ListView.builder(
          itemCount: _activities.length,
          itemBuilder: (context, i) {
            // you can return a card here.
            return ListTile(
              title: Text(_activities[i].query),
            );
          },
        );
      },
    ),
  );
}