import 'package:flutter/material.dart'; import 'package:localization/localization.dart'; import 'package:loris/partials/thread.dart'; import '../../business_logic/timeline/timeline.dart' as tl; class Timeline extends StatefulWidget { const Timeline({Key? key}) : super(key: key); @override State createState() => _TimelineState(); } class _TimelineState extends State with AutomaticKeepAliveClientMixin { String? oldestId; final controller = ScrollController(); List children = []; bool loading = false; @override void initState() { super.initState(); children.add(const LoadingBox()); fetchMore(); controller.addListener(() { if (controller.position.maxScrollExtent <= controller.offset + 2 * MediaQuery.of(context).size.height && !loading) { fetchMore(); } }); } Future fetchMore() async { while (loading) { await Future.delayed(const Duration(milliseconds: 500)); } loading = true; final models = await tl.getTimelineFromServer(oldestId); setState(() { children.removeWhere((element) { return element.runtimeType != Thread; }); List threads = []; for (int i = 0; i < models.length; i++) { threads.add(Thread(model: models[i])); } oldestId = models.last.posts.last.id; children.addAll(threads); children.add( Row( mainAxisAlignment: MainAxisAlignment.center, children: [ TextButton.icon( onPressed: () { fetchMore(); }, icon: const Icon(Icons.more_horiz), label: Text("load-more".i18n()), ) ], ), ); children.add(const LoadingBox()); loading = false; }); } @override void dispose() { controller.dispose(); super.dispose(); } @override Widget build(BuildContext context) { super.build(context); return ListView.separated( physics: const AlwaysScrollableScrollPhysics(), controller: controller, itemBuilder: (context, index) { return children[index]; }, separatorBuilder: (context, index) { return const Divider( color: Colors.transparent, ); }, itemCount: children.length, padding: const EdgeInsets.fromLTRB(24, 0, 24, 64), addAutomaticKeepAlives: false, ); } @override bool get wantKeepAlive => true; } class LoadingBox extends StatelessWidget { const LoadingBox({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return SizedBox.fromSize( size: Size(double.infinity, MediaQuery.of(context).size.height), child: Center( child: SizedBox.fromSize( size: const Size(128, 128), child: const CircularProgressIndicator(), ), )); } }