infinite_grouped_list 1.2.6 copy "infinite_grouped_list: ^1.2.6" to clipboard
infinite_grouped_list: ^1.2.6 copied to clipboard

Dynamic scrolling list in Flutter, efficiently grouping items and seamlessly loading more data as user scrolls

example/lib/main.dart

import 'dart:math';

import 'package:flutter/material.dart';
import 'package:infinite_grouped_list/infinite_grouped_list.dart';

enum TransactionType {
  transport,
  food,
  shopping,
  entertainment,
  health,
  other,
}

class Transaction {
  final String name;
  final DateTime dateTime;
  final double amount;
  final TransactionType type;
  Transaction({
    required this.name,
    required this.dateTime,
    required this.amount,
    required this.type,
  });

  @override
  String toString() {
    return '{name: $name, dateTime: $dateTime}';
  }
}

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  bool dontThrowError = false;

  DateTime baseDate = DateTime.now();
  InfiniteGroupedListController<Transaction, DateTime, String> controller =
      InfiniteGroupedListController<Transaction, DateTime, String>();
  Future<List<Transaction>> onLoadMore(int offset) async {
    await Future.delayed(const Duration(seconds: 1));

    return List<Transaction>.generate(
      20,
      (index) {
        final tempDate = baseDate;
        baseDate = baseDate.subtract(const Duration(days: 1));
        return Transaction(
          name: 'Transaction num #$index',
          dateTime: tempDate,
          amount: Random().nextDouble() * 1000,
          type: TransactionType.values[Random().nextInt(6)],
        );
      },
    );
  }

  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.grey[100],
      appBar: AppBar(
        shadowColor: Colors.grey.withOpacity(0.2),
        title: const Text('Infinite Grouped List'),
        backgroundColor: Colors.white,
        centerTitle: true,
        elevation: 5,
      ),
      body: InfiniteGroupedList(
        groupBy: (item) => item.dateTime,
        controller: controller,
        sortGroupBy: (item) => item.dateTime,
        initialItemsErrorWidget: (error) => GestureDetector(
          child: Text(
            error.toString(),
            textAlign: TextAlign.center,
            style: const TextStyle(
              fontSize: 15,
              fontWeight: FontWeight.w500,
              decoration: TextDecoration.underline,
              decorationColor: Colors.blue,
              color: Colors.blue,
            ),
          ),
        ),
        groupTitleBuilder: (title, groupBy, isPinned, scrollPercentage) =>
            Padding(
          padding: const EdgeInsets.only(bottom: 12.0, top: 12.0),
          child: Container(
            padding: const EdgeInsets.all(8.0),
            decoration: BoxDecoration(
              color: Colors.white,
              borderRadius: BorderRadius.circular(10),
              boxShadow: const [
                BoxShadow(
                  color: Colors.black12,
                  blurRadius: 5,
                  offset: Offset(0, 2),
                ),
              ],
            ),
            child: Padding(
              padding: const EdgeInsets.all(8.0),
              child: Text(
                title,
                style: const TextStyle(
                  fontSize: 16,
                  fontWeight: FontWeight.bold,
                ),
              ),
            ),
          ),
        ),
        itemBuilder: (item) => ListTile(
          onTap: () {
            controller.remove(item);
          },
          title: Text(item.name),
          leading: item.type == TransactionType.transport
              ? const Icon(Icons.directions_bus)
              : item.type == TransactionType.food
                  ? const Icon(Icons.fastfood)
                  : item.type == TransactionType.shopping
                      ? const Icon(Icons.shopping_bag)
                      : item.type == TransactionType.entertainment
                          ? const Icon(Icons.movie)
                          : item.type == TransactionType.health
                              ? const Icon(Icons.medical_services)
                              : const Icon(Icons.money),
          trailing: Text(
            '${item.amount.toStringAsFixed(2)}€',
            style: const TextStyle(
              fontSize: 16,
              fontWeight: FontWeight.bold,
            ),
          ),
          subtitle: Text(item.dateTime.toIso8601String()),
        ),
        onLoadMore: (info) => onLoadMore(info.offset),
        groupCreator: (dateTime) {
          final now = DateTime.now();
          final today = DateTime(now.year, now.month, now.day);
          final yesterday = today.subtract(const Duration(days: 1));
          final lastWeek = today.subtract(const Duration(days: 7));
          final lastMonth = DateTime(today.year, today.month - 1, today.day);

          if (today.day == dateTime.day &&
              today.month == dateTime.month &&
              today.year == dateTime.year) {
            return 'Today';
          } else if (yesterday.day == dateTime.day &&
              yesterday.month == dateTime.month &&
              yesterday.year == dateTime.year) {
            return 'Yesterday';
          } else if (lastWeek.isBefore(dateTime) &&
              dateTime.isBefore(yesterday)) {
            return 'Last Week';
          } else if (lastMonth.isBefore(dateTime) &&
              dateTime.isBefore(lastWeek)) {
            return 'Last Month';
          } else {
            // Convert the DateTime to a string for grouping
            return '${dateTime.year}-${dateTime.month}-${dateTime.day}';
          }
        },
      ),
    );
  }
}
22
likes
140
pub points
79%
popularity
screenshot

Publisher

verified publisheresentis.dev

Dynamic scrolling list in Flutter, efficiently grouping items and seamlessly loading more data as user scrolls

Repository (GitHub)
View/report issues

Documentation

API reference

License

BSD-3-Clause (LICENSE)

Dependencies

flutter, flutter_sticky_header, lint, test

More

Packages that depend on infinite_grouped_list