This example demonstrates making an optimal infinite list. That is, when you infinitely scroll down to load new items,
the older items are unloaded from memory.
The "loading" action is performed on a worker thread and a delay is simulated by AThread::sleep.
As a bonus, we've added a spinner to indicate that loading is in progress.
In this example, we've used functional style and decomposition technique instead of making custom view classes. The idea
is hide the implementation specifics of myLazyList that makes a basic AView in return. The overall state of produced
lazy list object is controlled by list model.
myLazyList is limited to specific type of model by intention. AUI does not provide some kind of generalization on its
own. In fact, we're demonstrating the whole concept in less than 100 lines of code. You certainly can make a
generalization that suits your project's needs.
#include<range/v3/all.hpp>#include<AUI/Platform/Entry.h>#include"AUI/Platform/AWindow.h"#include"AUI/Util/UIBuildingHelpers.h"#include"AUI/View/AScrollArea.h"#include"AUI/View/ASpinnerV2.h"#include"AUI/View/AForEachUI.h"#include"AUI/Model/AListModel.h"#include"AUI/Thread/AAsyncHolder.h"usingnamespacedeclarative;usingnamespaceass;usingnamespacestd::chrono_literals;structItem{AProperty<AString>value;};structState{AProperty<AVector<_<Item>>>items;AProperty<bool>needMore=false;AAsyncHolderasyncTasks;};_<AView>myLazyList(_<State>state){// note that we observe for transition to true here, not the current state of property// see PropertyTest_Observing_changes for more infoAObject::connect(state->needMore.changed,AObject::GENERIC_OBSERVER,[state](boolnewState){if(!newState){// we're interested in transitions to true state only.return;}autoloadFrom=state->items->size();// base index to load from.state->asyncTasks<<AUI_THREADPOOL{// perform "loading" task on a worker thread.AThread::sleep(500ms);// imitate hard work here// aka "loaded" from backend storage of some kindautoloadedItems=AVector<_<Item>>::generate(20,[&](size_ti){returnaui::ptr::manage_shared(newItem{.value="Item {}"_format(loadFrom+i)});});AUI_UI_THREAD{// back to main thread.state->items.writeScope()->insertAll(loadedItems);state->needMore=false;};};});returnVertical{AUI_DECLARATIVE_FOR(i,*state->items,AVerticalLayout){returnLabel{}&i->value;},Centered{_new<ASpinnerV2>()AUI_LET{AObject::connect(it->redrawn,AObject::GENERIC_OBSERVER,[state]{// when a spinner appears, we indicate that we need more items.state->needMore=true;});},},};}AUI_ENTRY{autowindow=_new<AWindow>("Infinite Lazy List",200_dp,300_dp);window->setContents(Stacked{AScrollArea::Builder().withContents(myLazyList(_new<State>()))});window->show();return0;}