@@ -24,10 +24,11 @@ public class Views.Filter : Adw.Bin {
2424 private Gtk . Image title_icon;
2525 private Gtk . Label title_label;
2626 private Gtk . ListBox listbox;
27- private Adw . Bin listbox_content;
2827 private Gtk . Stack listbox_stack;
2928 private Widgets . MagicButton magic_button;
3029 private Gtk . Revealer view_setting_revealer;
30+ private Gtk . Button load_more_button;
31+ private Gtk . Revealer load_more_button_revealer;
3132
3233 private Gee . HashMap<string, Layouts . ItemRow > items = new Gee .HashMap<string, Layouts . ItemRow > ();
3334 private Gee . HashMap<ulong, weak GLib . Object > signals_map = new Gee .HashMap<ulong, weak GLib . Object > ();
@@ -51,6 +52,10 @@ public class Views.Filter : Adw.Bin {
5152 }
5253 }
5354
55+ private Gee . ArrayList<Objects . Item > items_list;
56+ private int page_index = 0 ;
57+ private const int PAGE_SIZE = Constants . COMPLETED_PAGE_SIZE ;
58+
5459 ~Filter () {
5560 print (" Destroying Views.Filter\n " );
5661 }
@@ -101,11 +106,24 @@ public class Views.Filter : Adw.Bin {
101106 css_classes = { " listbox-background" }
102107 };
103108
104- listbox_content = new Adw .Bin () {
105- child = listbox,
109+ load_more_button = new Gtk .Button .with_label (" Cargar más" ) {
110+ margin_start = 9 ,
111+ halign = START ,
112+ };
113+ load_more_button.add_css_class ("flat ");
114+
115+ load_more_button_revealer = new Gtk .Revealer () {
116+ transition_type = Gtk . RevealerTransitionType . SLIDE_DOWN ,
117+ reveal_child = false ,
118+ child = load_more_button
119+ };
120+
121+ var listbox_box = new Gtk .Box (VERTICAL , 12 ) {
106122 margin_end = 24 ,
107123 margin_top = 12
108124 };
125+ listbox_box.append (listbox );
126+ listbox_box.append (load_more_button_revealer );
109127
110128 var listbox_placeholder = new Adw .StatusPage ();
111129 listbox_placeholder. icon_name = " check-round-outline-symbolic" ;
@@ -118,7 +136,7 @@ public class Views.Filter : Adw.Bin {
118136 transition_type = Gtk . StackTransitionType . CROSSFADE
119137 };
120138
121- listbox_stack.add_named (listbox_content , "listbox ");
139+ listbox_stack.add_named (listbox_box , "listbox ");
122140 listbox_stack.add_named (listbox_placeholder , "placeholder ");
123141
124142 var content = new Gtk .Box (Gtk . Orientation . VERTICAL , 0 ) {
@@ -129,7 +147,7 @@ public class Views.Filter : Adw.Bin {
129147 content.append (title_box );
130148 content.append (listbox_stack );
131149
132- var content_clamp = new Adw .ClampScrollable () {
150+ var content_clamp = new Adw .Clamp () {
133151 maximum_size = 864 ,
134152 margin_bottom = 64 ,
135153 child = content
@@ -191,6 +209,10 @@ public class Views.Filter : Adw.Bin {
191209 signals_map[scrolled_window.vadjustment.value_changed.connect (() => {
192210 headerbar. revealer_title_box (scrolled_window. vadjustment. value >= Constants . HEADERBAR_TITLE_SCROLL_THRESHOLD );
193211 })] = scrolled_window. vadjustment;
212+
213+ signals_map[load_more_button.clicked.connect (() => {
214+ load_next_page ();
215+ })] = load_more_button;
194216 }
195217
196218 public void prepare_new_item (string content = " " ) {
@@ -222,63 +244,55 @@ public class Views.Filter : Adw.Bin {
222244 Util . get_default (). set_widget_color (priority. color, title_icon);
223245
224246 title_label. label = priority. name;
225- listbox. set_sort_func (null );
226- listbox. set_header_func (null );
247+ listbox. set_header_func (header_project_function);
227248 magic_button. visible = true ;
228249 } else if (filter is Objects . Filters . Completed ) {
229250 title_icon. icon_name = FilterType . COMPLETED. get_icon ();
230251 Util . get_default (). set_widget_color (FilterType . COMPLETED. get_color (), title_icon);
231252
232253 title_label. label = FilterType . COMPLETED. get_name ();
233- listbox. set_sort_func (sort_completed_function);
234254 listbox. set_header_func (header_completed_function);
235255 magic_button. visible = false ;
236256 } else if (filter is Objects . Filters . Tomorrow ) {
237257 title_icon. icon_name = FilterType . SCHEDULED. get_icon ();
238258 Util . get_default (). set_widget_color (FilterType . SCHEDULED. get_color (), title_icon);
239259
240260 title_label. label = _(" Tomorrow" );
241- listbox. set_sort_func (null );
242- listbox. set_header_func (null );
261+ listbox. set_header_func (header_project_function);
243262 magic_button. visible = true ;
244263 } else if (filter is Objects . Filters . Pinboard ) {
245264 title_icon. icon_name = FilterType . PINBOARD. get_icon ();
246265 Util . get_default (). set_widget_color (FilterType . PINBOARD. get_color (), title_icon);
247266
248267 title_label. label = FilterType . PINBOARD. get_name ();
249- listbox. set_sort_func (null );
250- listbox. set_header_func (null );
268+ listbox. set_header_func (header_project_function);
251269 magic_button. visible = true ;
252270 } else if (filter is Objects . Filters . Anytime ) {
253271 title_icon. icon_name = FilterType . SCHEDULED. get_icon ();
254272 Util . get_default (). set_widget_color (FilterType . SCHEDULED. get_color (), title_icon);
255273
256274 title_label. label = _(" Anytime" );
257- listbox. set_sort_func (sort_project_function);
258275 listbox. set_header_func (header_project_function);
259276 magic_button. visible = true ;
260277 } else if (filter is Objects . Filters . Repeating ) {
261278 title_icon. icon_name = " arrow-circular-top-right-symbolic" ;
262279 Util . get_default (). set_widget_color (FilterType . SCHEDULED. get_color (), title_icon);
263280
264281 title_label. label = _(" Repeating" );
265- listbox. set_sort_func (sort_project_function);
266282 listbox. set_header_func (header_project_function);
267283 magic_button. visible = false ;
268284 } else if (filter is Objects . Filters . Unlabeled ) {
269285 title_icon. icon_name = " tag-outline-symbolic" ;
270286 Util . get_default (). set_widget_color (FilterType . LABELS. get_color (), title_icon);
271287
272288 title_label. label = _(" Unlabeled" );
273- listbox. set_sort_func (sort_project_function);
274289 listbox. set_header_func (header_project_function);
275290 magic_button. visible = true ;
276291 } else if (filter is Objects . Filters . AllItems ) {
277292 title_icon. icon_name = " grid-large-symbolic" ;
278293 Util . get_default (). set_widget_color (FilterType . INBOX. get_color (), title_icon);
279294
280295 title_label. label = _(" All Tasks" );
281- listbox. set_sort_func (sort_project_function);
282296 listbox. set_header_func (header_project_function);
283297 magic_button. visible = true ;
284298 }
@@ -295,40 +309,94 @@ public class Views.Filter : Adw.Bin {
295309
296310 items. clear ();
297311
312+ if (items_list == null ) {
313+ items_list = new Gee .ArrayList<Objects . Item > ();
314+ } else {
315+ items_list. clear ();
316+ }
317+
298318 if (filter is Objects . Filters . Priority ) {
299319 Objects . Filters . Priority priority = ((Objects . Filters . Priority ) filter);
300320 foreach (Objects . Item item in Services . Store . instance (). get_items_by_priority (priority. priority, false )) {
301- add_item (item);
321+ items_list . add (item);
302322 }
303323 } else if (filter is Objects . Filters . Completed ) {
304324 foreach (Objects . Item item in Services . Store . instance (). get_items_completed ()) {
305- add_item (item);
325+ items_list . add (item);
306326 }
307327 } else if (filter is Objects . Filters . Tomorrow ) {
308328 foreach (Objects . Item item in Services . Store . instance (). get_items_by_date (new GLib .DateTime .now_local (). add_days (1 ), false )) {
309- add_item (item);
329+ items_list . add (item);
310330 }
311331 } else if (filter is Objects . Filters . Pinboard ) {
312332 foreach (Objects . Item item in Services . Store . instance (). get_items_pinned (false )) {
313- add_item (item);
333+ items_list . add (item);
314334 }
315335 } else if (filter is Objects . Filters . Anytime ) {
316336 foreach (Objects . Item item in Services . Store . instance (). get_items_no_date (false )) {
317- add_item (item);
337+ items_list . add (item);
318338 }
319339 } else if (filter is Objects . Filters . Repeating ) {
320340 foreach (Objects . Item item in Services . Store . instance (). get_items_repeating (false )) {
321- add_item (item);
341+ items_list . add (item);
322342 }
323343 } else if (filter is Objects . Filters . Unlabeled ) {
324344 foreach (Objects . Item item in Services . Store . instance (). get_items_unlabeled (false )) {
325- add_item (item);
345+ items_list . add (item);
326346 }
327347 } else if (filter is Objects . Filters . AllItems ) {
328348 foreach (Objects . Item item in Services . Store . instance (). get_items_no_parent (false )) {
329- add_item (item);
349+ items_list . add (item);
330350 }
331351 }
352+
353+ if (filter is Objects . Filters . Completed ) {
354+ items_list. sort ((a, b) = > {
355+ var completed_a = Utils . Datetime . get_date_only (
356+ Utils . Datetime . get_date_from_string (a. completed_at)
357+ );
358+
359+ var completed_b = Utils . Datetime . get_date_only (
360+ Utils . Datetime . get_date_from_string (b. completed_at)
361+ );
362+
363+ return completed_b. compare (completed_a);
364+ });
365+ } else {
366+ items_list. sort ((a, b) = > {
367+ return a. project_id. strip (). collate (b. project_id. strip ());
368+ });
369+ }
370+
371+ page_index = 0 ;
372+ load_next_page ();
373+ }
374+
375+ private void load_next_page () {
376+ int start = page_index * PAGE_SIZE ;
377+ int end = (start + PAGE_SIZE < items_list. size) ? (start + PAGE_SIZE ) : items_list. size;
378+
379+ for (int i = start; i < end; i++ ) {
380+ Objects . Item item = items_list[i];
381+ add_item (item);
382+ }
383+
384+ page_index++ ;
385+ update_load_more_button_label ();
386+ }
387+
388+ private void update_load_more_button_label () {
389+ int loaded = page_index * PAGE_SIZE ;
390+ int remaining = items_list. size - loaded;
391+
392+ if (remaining > 0 ) {
393+ int to_show = remaining < PAGE_SIZE ? remaining : PAGE_SIZE ;
394+ load_more_button. label = " +%d %s " . printf (to_show, _ (" completed tasks" ));
395+ load_more_button_revealer. reveal_child = true ;
396+ } else {
397+ load_more_button. set_label (" No more tasks" );
398+ load_more_button_revealer. reveal_child = false ;
399+ }
332400 }
333401
334402 private void add_item (Objects . Item item) {
@@ -522,22 +590,6 @@ public class Views.Filter : Adw.Bin {
522590 row. set_header (get_header_box (row. item. project. name));
523591 }
524592
525- private int sort_completed_function (Gtk . ListBoxRow row1, Gtk . ListBoxRow ? row2) {
526- var completed_a = Utils . Datetime . get_date_only (
527- Utils . Datetime . get_date_from_string (((Widgets . CompletedTaskRow ) row1). item. completed_at)
528- );
529- var completed_b = Utils . Datetime . get_date_only (
530- Utils . Datetime . get_date_from_string (((Widgets . CompletedTaskRow ) row2). item. completed_at)
531- );
532- return completed_b. compare (completed_a);
533- }
534-
535- private int sort_project_function (Gtk . ListBoxRow row1, Gtk . ListBoxRow ? row2) {
536- var item1 = ((Layouts . ItemRow ) row1). item;
537- var item2 = ((Layouts . ItemRow ) row2). item;
538- return item1. project_id. strip (). collate (item2. project_id. strip ());
539- }
540-
541593 private void validate_placeholder () {
542594 listbox_stack. visible_child_name = has_items ? " listbox" : " placeholder" ;
543595 }
@@ -601,10 +653,13 @@ public class Views.Filter : Adw.Bin {
601653 }
602654
603655 public void clean_up () {
656+ listbox. set_sort_func (null );
657+ listbox. set_header_func (null );
658+
604659 foreach (var entry in signals_map. entries) {
605660 entry. value . disconnect (entry. key);
606661 }
607662
608663 signals_map. clear ();
609664 }
610- }
665+ }
0 commit comments