display favicons (fixes #6)

This commit is contained in:
Lea 2023-01-30 08:28:21 +01:00
parent 27915caf5f
commit 3270f5d888
Signed by: Lea
GPG key ID: 1BAFFE8347019C42
5 changed files with 70 additions and 10 deletions

View file

@ -8,6 +8,7 @@ import 'package:crypto/crypto.dart';
part 'feed.dart';
part 'item.dart';
part 'group.dart';
part 'favicon.dart';
part 'feeds_group.dart';
part 'cache.dart';
part 'exceptions.dart';
@ -103,6 +104,11 @@ class APIRequestBuilder {
return this;
}
APIRequestBuilder withFavicons() {
_addArg("favicons");
return this;
}
/// Mark single item as read, unread, saved, unsaved
APIRequestBuilder markItem(Item item, ItemMarkType markAs) {
_addArg('mark=item');
@ -176,6 +182,16 @@ class APIRequestBuilder {
}
}
if (data.containsKey('favicons')) {
List<Favicon> favicons = (data['favicons'] as List<dynamic>)
.map((json) => Favicon.fromJSON(api, json))
.toList();
for (var favicon in favicons) {
api.cache.favicons.set(favicon.id, favicon);
}
}
if (data.containsKey('feeds_groups')) {
List<FeedsGroup> feedsGroups = (data['feeds_groups'] as List<dynamic>)
.map((json) => FeedsGroup.fromJSON(api, json))

View file

@ -7,18 +7,21 @@ class APICache {
late final ItemCache items;
late final ObjectCache<int, Feed> feeds;
late final ObjectCache<int, Group> groups;
late final ObjectCache<int, Favicon> favicons;
final List<FeedsGroup> feedsGroups = [];
APICache(this.api) {
items = ItemCache(api);
feeds = ObjectCache(api);
groups = ObjectCache(api);
favicons = ObjectCache(api);
}
void clear() {
items._items.clear();
feeds._items.clear();
groups._items.clear();
favicons._items.clear();
feedsGroups.clear();
}
}

23
lib/api/favicon.dart Normal file
View file

@ -0,0 +1,23 @@
part of fever_api;
class Favicon {
FeverAPI api;
late int id;
/// base64 encoded image data; prefixed by image type. Example:
/// `image/gif;base64,R0lGODlhAQABAIAAAObm5gAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==`
late String data;
Favicon(
this.api,
{
required this.id,
required this.data,
}
);
Favicon.fromJSON(this.api, Map<String, dynamic> json) {
id = toInt(json['id']);
data = json['data'];
}
}

View file

@ -100,6 +100,7 @@ class _MyHomePageState extends State<MyHomePage> {
.request()
.withFeeds()
.withGroups()
.withFavicons()
.withItems()
.sinceId(0)
.execute();
@ -139,9 +140,8 @@ class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
var loggedIn = widget.api.loggedIn();
var posts = widget.api.cache.items.getAll().values.where(
(element) => _feedFilter.isEmpty || _feedFilter.contains(element.feedId)
);
var posts = widget.api.cache.items.getAll().values.where((element) =>
_feedFilter.isEmpty || _feedFilter.contains(element.feedId));
var savedPosts = posts.where((element) => element.isSaved);
var unreadPosts = posts.where((element) => !element.isRead);
@ -260,11 +260,9 @@ class _MyHomePageState extends State<MyHomePage> {
),
PopupMenuItem(
value: "filter",
child: Text(
_feedFilter.isEmpty
child: Text(_feedFilter.isEmpty
? "Filter..."
: "Filter (${_feedFilter.length}/${widget.api.cache.feeds.size})"
),
: "Filter (${_feedFilter.length}/${widget.api.cache.feeds.size})"),
onTap: () {
Future.delayed(
Duration.zero,

View file

@ -1,3 +1,5 @@
import 'dart:convert';
import 'package:feet/pages/article.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
@ -20,6 +22,8 @@ class _HomepagePostState extends State<HomepagePost> {
@override
Widget build(BuildContext context) {
var post = widget.post;
var favicon = post.api.cache.favicons.get(post.feedId);
return Container(
margin: const EdgeInsets.symmetric(vertical: 6.0, horizontal: 8.0),
decoration: BoxDecoration(
@ -69,9 +73,25 @@ class _HomepagePostState extends State<HomepagePost> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(post.title,
style: Theme.of(context).textTheme.titleMedium,
overflow: TextOverflow.ellipsis),
Row(
children: [
favicon?.data != null
? Container(
margin: const EdgeInsets.fromLTRB(0, 0, 6, 4),
child: Image.memory(
base64Decode(favicon!.data.split(',')[1]),
width: 20,
height: 20,
),
)
: Container(),
Expanded(
child: Text(post.title,
style: Theme.of(context).textTheme.titleMedium,
overflow: TextOverflow.ellipsis),
),
],
),
ClipRRect(
clipBehavior: Clip.antiAlias,
child: Row(