fetch all posts instead of only the initial 50

This commit is contained in:
Lea 2023-01-23 08:47:10 +01:00
parent 1a09ba2ba9
commit 2303df7abe
Signed by: Lea
GPG key ID: 1BAFFE8347019C42
4 changed files with 71 additions and 7 deletions

View file

@ -103,6 +103,7 @@ class APIRequestBuilder {
return this; return this;
} }
/// Mark single item as read, unread, saved, unsaved
APIRequestBuilder markItem(Item item, ItemMarkType markAs) { APIRequestBuilder markItem(Item item, ItemMarkType markAs) {
_addArg('mark=item'); _addArg('mark=item');
_addArg('as=${markAs.name}'); _addArg('as=${markAs.name}');
@ -112,6 +113,22 @@ class APIRequestBuilder {
return this; return this;
} }
/// Use the `since_id` argument with the highest id of locally cached items to
/// request 50 additional items. Repeat until the items array in the response
/// is empty.
APIRequestBuilder sinceId(int id) {
_addArg('since_id=$id');
return this;
}
/// Use the `max_id` argument with the lowest id of locally cached items (or
/// 0 initially) to request 50 previous items. Repeat until the items array
/// in the response is empty.
APIRequestBuilder maxId(int id) {
_addArg('max_id=$id');
return this;
}
/// Executes the API request and returns the JSON data /// Executes the API request and returns the JSON data
Future<Map<String, dynamic>> fetch() async { Future<Map<String, dynamic>> fetch() async {
if (api.apiKey == null || api.apiUrl == null) { if (api.apiKey == null || api.apiUrl == null) {
@ -126,7 +143,7 @@ class APIRequestBuilder {
} }
/// Executes the API request and populates the local cache with the response data /// Executes the API request and populates the local cache with the response data
Future<void> execute() async { Future<Map<String, dynamic>> execute() async {
final data = await fetch(); final data = await fetch();
if (data.containsKey('groups')) { if (data.containsKey('groups')) {
@ -185,6 +202,8 @@ class APIRequestBuilder {
} }
api.cache.items.set(_markedItem!.id, _markedItem!); api.cache.items.set(_markedItem!.id, _markedItem!);
} }
return data;
} }
} }

View file

@ -42,6 +42,8 @@ class ObjectCache<K, T> {
void set(K key, T value) { void set(K key, T value) {
_items[key] = value; _items[key] = value;
} }
int get size => _items.length;
} }
class ItemCache extends ObjectCache<int, Item> { class ItemCache extends ObjectCache<int, Item> {

View file

@ -1,6 +1,5 @@
import 'dart:async'; import 'dart:async';
import 'package:feet/pages/login.dart';
import 'package:feet/widgets/centered_page_hint.dart'; import 'package:feet/widgets/centered_page_hint.dart';
import 'package:feet/widgets/homepage_post.dart'; import 'package:feet/widgets/homepage_post.dart';
import 'package:feet/widgets/login_prompt.dart'; import 'package:feet/widgets/login_prompt.dart';
@ -10,6 +9,10 @@ import 'package:flutter/services.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import 'api/api.dart'; import 'api/api.dart';
// Limit the maximum amount of posts to fetch so we don't wait forever when
// fetching a large list
const FETCH_MAX_POSTS = 1000;
void main() { void main() {
runApp(MyApp()); runApp(MyApp());
} }
@ -78,9 +81,47 @@ class MyHomePage extends StatefulWidget {
class _MyHomePageState extends State<MyHomePage> { class _MyHomePageState extends State<MyHomePage> {
var _index = 0; var _index = 0;
var _fetched = false; var _fetched = false;
var _fetchedCount = 0;
var _knownPostsSize = -1;
Future<void> refresh() => Future<void> refresh() async {
widget.api.request().withFeeds().withGroups().withItems().execute(); widget.api.cache.clear();
print("Starting refresh");
var data = await widget.api
.request()
.withFeeds()
.withGroups()
.withItems()
.sinceId(0)
.execute();
while (
(data['items'] as List<dynamic>).isNotEmpty &&
_fetchedCount < FETCH_MAX_POSTS
) {
print("Fetching more items");
var ids = widget.api.cache.items
.getAll()
.values
.map((value) => value.id)
.toList()
..sort((a, b) => b - a);
setState(() {
_fetchedCount = ids.length;
_knownPostsSize = data['total_items'] ?? -1;
});
data =
await widget.api.request().withItems().sinceId(ids.first).execute();
print(
"Item cache size is now ${widget.api.cache.items.size} ${ids.first} ${ids.last}");
}
}
@override @override
void initState() { void initState() {
@ -233,8 +274,10 @@ class _MyHomePageState extends State<MyHomePage> {
body: loggedIn body: loggedIn
? (_fetched ? (_fetched
? pages[_index] ? pages[_index]
: const CenteredPageHint( : CenteredPageHint(
icon: Icons.downloading, text: "Fetching your feeds...")) icon: Icons.downloading,
text:
"Fetching your feeds...\n${_fetchedCount > 0 && _knownPostsSize > -1 ? "$_fetchedCount / $_knownPostsSize" : ""}"))
: Center(child: LoginPrompt(api: widget.api)), : Center(child: LoginPrompt(api: widget.api)),
); );
} }

View file

@ -15,7 +15,7 @@ class CenteredPageHint extends StatelessWidget {
padding: const EdgeInsets.all(12.0), padding: const EdgeInsets.all(12.0),
child: Icon(icon, size: 48), child: Icon(icon, size: 48),
), ),
Text(text), Text(text, textAlign: TextAlign.center),
], ],
), ),
); );