display favicons (fixes #6)
This commit is contained in:
parent
27915caf5f
commit
3270f5d888
|
@ -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))
|
||||
|
|
|
@ -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
23
lib/api/favicon.dart
Normal 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'];
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
|
|
|
@ -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(
|
||||
|
|
Loading…
Reference in a new issue