user8239476
user8239476

Reputation:

Building and sorting a new list based on provided list and parameters

I have a list of Models:

class Model {
final DateTime date;
final String text;

Model({this.date, this.text});
}

List<Model> _models = [
Model(date: DateTime(2018, 9, 1), text: 'Text1',),
Model(date: DateTime(2018, 9, 1), text: 'Text2',),
Model(date: DateTime(2018, 9, 2), text: 'Text3',),
Model(date: DateTime(2018, 9, 3), text: 'Text4',),
Model(date: DateTime(2018, 8, 31), text: 'Text7',),
Model(date: DateTime(2018, 9, 3), text: 'Text5',),
Model(date: DateTime(2018, 9, 3), text: 'Text6',),
];

What I am trying to achieve is to take the date parameter from each model and put all models that match that date into a ListView(). So I can return a list of models for each date. Every time I add data to the list I want it to update & sort by date automatically (no manual stuff). Date formatting is not important here. Question: how can I achieve that?

Here is how I want it to look like:
2018/9/3
Text4
Text5
Text6

2018/9/2
Text3

2018/9/1
Text1
Text2

2018/8/31
Text7

Upvotes: 3

Views: 4120

Answers (2)

1ujn4s
1ujn4s

Reputation: 489

For another bare-bone example involving no third-party packages:

import 'package:flutter/material.dart';

class Model {
  final DateTime date;
  final String text;

  Model({this.date, this.text});
}

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

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

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

class _MyHomePageState extends State<MyHomePage> {

  // Populate initial value for the list of models
  List<Model> _models = [
    Model(
      date: DateTime(2018, 9, 1),
      text: 'Text1',
    ),
    Model(
      date: DateTime(2018, 9, 1),
      text: 'Text2',
    ),
    Model(
      date: DateTime(2018, 9, 2),
      text: 'Text3',
    ),
    Model(
      date: DateTime(2018, 9, 3),
      text: 'Text4',
    ),
    Model(
      date: DateTime(2018, 8, 31),
      text: 'Text7',
    ),
    Model(
      date: DateTime(2018, 9, 3),
      text: 'Text5',
    ),
    Model(
      date: DateTime(2018, 9, 3),
      text: 'Text6',
    )
  ];

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text("Sample App"),
      ),
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.plus_one),
        onPressed: () {
          setState(() {

            // On click of floating action button, add a hardcoded item to _models list
            _models.add(Model(
              date: DateTime(2018, 9, 2),
              text: 'New Item',
            ));
          });
        },
      ),
      body: SortedGroupedList(_models),
    );
  }
}

class SortedGroupedList extends StatefulWidget {
  final List<Model> list;
  SortedGroupedList(this.list);

  @override
  State<StatefulWidget> createState() => _SortedGroupedListState();
}

class _SortedGroupedListState extends State<SortedGroupedList> {
  List<Model> _list;
  @override
  void initState() {
    super.initState();
    _list = widget.list;
  }

  @override
  Widget build(BuildContext context) {
    _list.sort((a, b) => b.date.compareTo(a.date));
    Model prev;
    bool shownHeader = false;

    List<Widget> _listChildren = <Widget>[];
    _list.forEach((Model model) {
      if (prev != null && model.date != prev.date) {
        shownHeader = false; // if dates are different, beginning of a new group, so header is yet to be shown
      }

      if (!shownHeader) {
        // if header for a group is not shown yet, add it to the list
        _listChildren.add(ListTile(
            title: Text(
          model.date.toString(),
          style: TextStyle(fontWeight: FontWeight.bold),
        )));
        prev = model; // keep the current model for reference to check if group has changed
        shownHeader = true;
      }

      _listChildren.add(ListTile(title: Text(model.text)));
    });

    return ListView(children: _listChildren);
  }
}

In this example, we create a new widget called SortedGroupedList, which will accept the models list and sort it in descending order, then display it using a ListView, while keeping track of items grouped by their dates.

Also the onPress of FloatingActionButton will add one more hard-coded item to the list when floating action buton is pressed, and that is reflected with 'no manual stuff' (whatever that is ;) ). This example can be improved to manipulate _model list and all the changes should ideally be reflected on our view.

Note that, this example may not be ideal for a huge list as the list have to be sorted everytime any changes are made to it. A better approach may be using the ListView.builder(), but that can get complex depending on the operations you want to perform on the list.

Upvotes: 1

1ujn4s
1ujn4s

Reputation: 489

For an easy solution using an existing widget; you may use side_header_list_view (https://pub.dartlang.org/packages/side_header_list_view)

example :

Widget _buildList(){ 

 return new SideHeaderListView(
      itemCount: _models.length,
      itemExtend: 100.0,
      headerBuilder: (BuildContext context, int index) {
        return Text(_models[index].date);
      },
      itemBuilder: (BuildContext context, int index) {
        return new Card(
          child: Text(_models[index].text),
        );
      },
      hasSameHeader: (int a, int b) {
        return _models[a].date == _models[b].date;
      },
    );

}

Haven't tested it, Ideally should work, provided, you might need to do some formatting of date to string type before giving it to Text.. Consider it like a pseudo code for now.

Upvotes: 2

Related Questions