diff options
author | Brendan Long <self@brendanlong.com> | 2017-10-21 20:16:07 +0300 |
---|---|---|
committer | Brendan Long <self@brendanlong.com> | 2017-10-21 20:16:07 +0300 |
commit | b5e91273107deb7b1c7125b73e4d6509fb04bc80 (patch) | |
tree | 7b876a9d31e8606b0c0f2ea17761a019133fe3cf | |
parent | fc37ff703fc83aeb3e49742858d55974cd9eb5da (diff) |
Turn FavIcon into a class instead of FavIconManager
This let us keep track of multiple things much easier.
-rw-r--r-- | CMakeLists.txt | 2 | ||||
-rw-r--r-- | plugins/backend/local/SuggestedFeedRow.vala | 7 | ||||
-rw-r--r-- | src/FavIcon.vala (renamed from src/FavIconManager.vala) | 190 | ||||
-rw-r--r-- | src/Utils.vala | 4 | ||||
-rw-r--r-- | src/Widgets/ArticleRow.vala | 30 | ||||
-rw-r--r-- | src/Widgets/FeedRow.vala | 37 |
6 files changed, 126 insertions, 144 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 02b5f2f3..2fae0670 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -98,7 +98,7 @@ set(UI_PACKAGES gio-2.0) vala_precompile(FEEDREADER ${FEEDREADER_NAME} - src/FavIconManager.vala + src/FavIcon.vala src/FeedReader.vala src/Widgets/AddPopover.vala src/Widgets/ArticleRow.vala diff --git a/plugins/backend/local/SuggestedFeedRow.vala b/plugins/backend/local/SuggestedFeedRow.vala index f9913106..b4a91cbd 100644 --- a/plugins/backend/local/SuggestedFeedRow.vala +++ b/plugins/backend/local/SuggestedFeedRow.vala @@ -71,14 +71,11 @@ public class FeedReader.SuggestedFeedRow : Gtk.ListBoxRow { private async void load_favicon(Gtk.Stack iconStack, Feed feed, string iconURL) { Gtk.Image? icon = null; - var pixBuf = yield FavIconManager.get_default().getIcon(feed); + var pixBuf = yield FavIcon.for_feed(feed).get_pixbuf(); if(pixBuf != null) icon = new Gtk.Image.from_pixbuf(pixBuf); - - if(icon == null) - { + else icon = new Gtk.Image.from_icon_name("feed-rss-symbolic", Gtk.IconSize.LARGE_TOOLBAR); - } iconStack.add_named(icon, "icon"); show_all(); diff --git a/src/FavIconManager.vala b/src/FavIcon.vala index 38243aaa..077a4479 100644 --- a/src/FavIconManager.vala +++ b/src/FavIcon.vala @@ -12,134 +12,134 @@ // // You should have received a copy of the GNU General Public License // along with FeedReader. If not, see <http://www.gnu.org/licenses/>. +public class FeedReader.FavIcon : GLib.Object +{ + private static string m_icon_path = GLib.Environment.get_user_data_dir() + "/feedreader/data/feed_icons/"; + private static Gee.Map<string, FavIcon> m_map = null; -public class FeedReader.FavIconManager : GLib.Object { - - private struct FavIconData + public static FavIcon for_feed(Feed feed) { - public Gdk.Pixbuf? icon; - public ResourceMetadata? metadata; + if(m_map == null) + m_map = new Gee.HashMap<string, FavIcon>(); - public FavIconData(Gdk.Pixbuf? icon, ResourceMetadata? meta) + var feed_id = feed.getFeedID(); + var icon = m_map.get(feed_id); + if(icon == null) { - this.metadata = meta; - this.icon = icon; + icon = new FavIcon(feed); + m_map.set(feed_id, icon); } + + return icon; } - private Gee.Map<string, Gee.Future<FavIconData?>> m_map = new Gee.HashMap<string, Gee.Future<FavIconData?>>(); - private static FavIconManager? m_cache = null; + private Feed m_feed; + private Gee.Promise<Gdk.Pixbuf?> m_icon = null; + private ResourceMetadata m_metadata; - public signal void ReloadFavIcon(Feed feed); + public signal void pixbuf_changed(Feed feed, Gdk.Pixbuf pixbuf); - public static FavIconManager get_default() + private FavIcon(Feed feed) { - if(m_cache == null) - m_cache = new FavIconManager(); - - return m_cache; + m_feed = feed; } - private FavIconManager() + public async Gdk.Pixbuf? get_pixbuf() { + if(m_icon == null || m_metadata.is_expired()) + { + m_icon = new Gee.Promise<Gdk.Pixbuf?>(); + load.begin((obj, res) => { + load.end(res); + }); + } + try + { + return yield m_icon.future.wait_async(); + } + catch(Error e) + { + Logger.error("FavIcon.get_pixbuf: " + e.message); + return null; + } } - public async Gdk.Pixbuf? getIcon(Feed feed) + private async void load() { try { - var feed_id = feed.getFeedID(); - var future = m_map.get(feed_id); + var stream = yield downloadFavIcon(); + if(stream == null) + return; - bool download_icon = future == null || (future.ready && (future.value.metadata == null || future.value.metadata.is_expired()) ); + var pixbuf = yield new Gdk.Pixbuf.from_stream_async(stream); + stream.close(); - if(download_icon) + if(pixbuf.get_height() <= 1 && pixbuf.get_width() <= 1) { - var promise = new Gee.Promise<FavIconData?>(); - try - { - future = promise.future; - m_map.set(feed_id, future); - - ResourceMetadata metadata; - var stream = yield downloadFavIcon(feed, out metadata); - if(stream == null) - return null; - - var pixbuf = yield new Gdk.Pixbuf.from_stream_async(stream); - stream.close(); - - if(pixbuf.get_height() <= 1 && pixbuf.get_width() <= 1) - { - Logger.warning("FavIconManager: Icon for feed %s is too small".printf(feed.getTitle())); - return null; - } - pixbuf = pixbuf.scale_simple(24, 24, Gdk.InterpType.BILINEAR); - - promise.set_value(FavIconData(pixbuf, metadata)); - ReloadFavIcon(feed); - } - finally - { - if(!future.ready) - promise.set_value(FavIconData(null, null)); - } + Logger.warning("FavIcon: Icon for feed %s is too small".printf(m_feed.getTitle())); + return; } + pixbuf = pixbuf.scale_simple(24, 24, Gdk.InterpType.BILINEAR); - FavIconData data = yield future.wait_async(); - return data.icon; + m_icon.set_value(pixbuf); + if(pixbuf != null) + pixbuf_changed(m_feed, pixbuf); } catch(Error e) { - Logger.error("FavIconManager.getIcon: %s".printf(e.message)); - return null; + Logger.error("FavIcon.load: " + e.message); + } + finally + { + if(!m_icon.future.ready) + m_icon.set_value(null); } } - private async InputStream? downloadFavIcon(Feed feed, out ResourceMetadata metadata, GLib.Cancellable? cancellable = null, string icon_path = GLib.Environment.get_user_data_dir() + "/feedreader/data/feed_icons/") throws GLib.Error + private async InputStream? downloadFavIcon(GLib.Cancellable? cancellable = null) throws GLib.Error { - string filename_prefix = icon_path + feed.getFeedFileName(); + string filename_prefix = m_icon_path + m_feed.getFeedFileName(); string local_filename = @"$filename_prefix.ico"; string metadata_filename = @"$filename_prefix.txt"; - metadata = yield ResourceMetadata.from_file_async(metadata_filename); - DateTime? expires = metadata.expires; + if(!yield Utils.ensure_path(m_icon_path)) + return null; + + m_metadata = yield ResourceMetadata.from_file_async(metadata_filename); + DateTime? expires = m_metadata.expires; if(cancellable != null && cancellable.is_cancelled()) return null; - var now = new DateTime.now_utc(); - if(expires != null) + if(!m_metadata.is_expired()) { - if(expires.to_unix() > now.to_unix()) + Logger.debug("Favicon for %s is valid until %s, skipping this time".printf(m_feed.getTitle(), expires.to_string())); + var file = File.new_for_path(local_filename); + try { - Logger.debug("Favicon for %s is valid until %s, skipping this time".printf(feed.getTitle(), expires.to_string())); - var file = File.new_for_path(local_filename); - try - { - return yield file.read_async(); - } - catch(IOError.NOT_FOUND e) - { - return null; - } + return yield file.read_async(); + } + catch(IOError.NOT_FOUND e) + { + return null; } } - var default_expires = now.add_days(Constants.REDOWNLOAD_FAVICONS_AFTER_DAYS); - if(metadata.expires == null || metadata.expires.to_unix() < default_expires.to_unix()) + var default_expires = new DateTime.now_utc().add_days(Constants.REDOWNLOAD_FAVICONS_AFTER_DAYS); + if(m_metadata.expires == null || m_metadata.expires.to_unix() < default_expires.to_unix()) { - metadata.expires = default_expires; - yield metadata.save_to_file_async(metadata_filename); + m_metadata.expires = default_expires; + yield m_metadata.save_to_file_async(metadata_filename); } var obvious_icons = new Gee.ArrayList<string>(); - if(feed.getIconURL() != null) - obvious_icons.add(feed.getIconURL()); + if(m_feed.getIconURL() != null) + obvious_icons.add(m_feed.getIconURL()); // try domainname/favicon.ico - var uri = new Soup.URI(feed.getURL()); + var uri = new Soup.URI(m_feed.getURL()); string? siteURL = null; if(uri != null) { @@ -156,7 +156,7 @@ public class FeedReader.FavIconManager : GLib.Object { // Try to find one of those icons foreach(var url in obvious_icons) { - var stream = yield downloadIcon(feed, url, cancellable, icon_path); + var stream = yield downloadIcon(url, cancellable); if(stream != null) return stream; @@ -210,7 +210,7 @@ public class FeedReader.FavIconManager : GLib.Object { if(xpath != null) { xpath = grabberUtils.completeURL(xpath, siteURL); - return yield downloadIcon(feed, xpath, cancellable, icon_path); + return yield downloadIcon(xpath, cancellable); } } finally @@ -222,7 +222,7 @@ public class FeedReader.FavIconManager : GLib.Object { return null; } - private async InputStream? downloadIcon(Feed feed, string? icon_url, Cancellable? cancellable, string icon_path = GLib.Environment.get_user_data_dir() + "/feedreader/data/feed_icons/") throws GLib.Error + private async InputStream? downloadIcon(string? icon_url, Cancellable? cancellable) throws GLib.Error { if(icon_url == "" || icon_url == null || GLib.Uri.parse_scheme(icon_url) == null) { @@ -230,16 +230,12 @@ public class FeedReader.FavIconManager : GLib.Object { return null; } - if(!yield Utils.ensure_path(icon_path)) - return null; - - string filename_prefix = icon_path + feed.getFeedFileName(); + string filename_prefix = m_icon_path + m_feed.getFeedFileName(); string local_filename = @"$filename_prefix.ico"; string metadata_filename = @"$filename_prefix.txt"; - var metadata = yield ResourceMetadata.from_file_async(metadata_filename); - string etag = metadata.etag; - string last_modified = metadata.last_modified; + string etag = m_metadata.etag; + string last_modified = m_metadata.last_modified; Logger.debug(@"Utils.downloadIcon: url = $icon_url"); var message = new Soup.Message("GET", icon_url); @@ -285,11 +281,11 @@ public class FeedReader.FavIconManager : GLib.Object { return null; } - metadata.etag = message.response_headers.get_one("ETag"); - metadata.last_modified = message.response_headers.get_one("Last-Modified"); + m_metadata.etag = message.response_headers.get_one("ETag"); + m_metadata.last_modified = message.response_headers.get_one("Last-Modified"); var cache_control = message.response_headers.get_list("Cache-Control"); - metadata.expires = new DateTime.now_utc().add_days(Constants.REDOWNLOAD_FAVICONS_AFTER_DAYS);; + m_metadata.expires = new DateTime.now_utc().add_days(Constants.REDOWNLOAD_FAVICONS_AFTER_DAYS); if(cache_control != null) { foreach(var header in message.response_headers.get_list("Cache-Control").split(",")) @@ -300,17 +296,17 @@ public class FeedReader.FavIconManager : GLib.Object { var seconds = int64.parse(parts[1]); var expires = new DateTime.now_utc(); expires.add_seconds(seconds); - if(expires.to_unix() > metadata.expires.to_unix()) - metadata.expires = expires; + if(expires.to_unix() > m_metadata.expires.to_unix()) + m_metadata.expires = expires; } } - metadata.last_modified = message.response_headers.get_one("Last-Modified"); - yield metadata.save_to_file_async(metadata_filename); + m_metadata.last_modified = message.response_headers.get_one("Last-Modified"); + yield m_metadata.save_to_file_async(metadata_filename); return new MemoryInputStream.from_data(data); } - Logger.warning(@"Could not download icon for feed: %s $icon_url, got response code $status".printf(feed.getFeedID())); + Logger.warning(@"Could not download icon for feed: %s $icon_url, got response code $status".printf(m_feed.getFeedID())); return null; } } diff --git a/src/Utils.vala b/src/Utils.vala index d2385e2f..7660bda3 100644 --- a/src/Utils.vala +++ b/src/Utils.vala @@ -548,6 +548,10 @@ public class FeedReader.Utils : GLib.Object { path.make_directory_with_parents(); return true; } + catch(IOError.EXISTS e) + { + return true; + } catch(Error e) { Logger.error(@"ensure_path: Failed to create folder $path_str: " + e.message); diff --git a/src/Widgets/ArticleRow.vala b/src/Widgets/ArticleRow.vala index 29bd6e6b..9e27fd01 100644 --- a/src/Widgets/ArticleRow.vala +++ b/src/Widgets/ArticleRow.vala @@ -147,10 +147,6 @@ public class FeedReader.ArticleRow : Gtk.ListBoxRow { m_marked_eventbox.button_press_event.connect(markedIconClicked); m_icon = createFavIcon(); - FavIconManager.get_default().ReloadFavIcon.connect(feed => { - if(m_article.getFeedID() == feed.getFeedID()) - reloadFavIcon.begin(); - }); icon_box.pack_start(m_icon, true, true, 0); icon_box.pack_end(m_unread_eventbox, false, false, 10); @@ -271,23 +267,21 @@ public class FeedReader.ArticleRow : Gtk.ListBoxRow { private Gtk.Image createFavIcon() { var icon = new Gtk.Image.from_icon_name("feed-rss-symbolic", Gtk.IconSize.LARGE_TOOLBAR); - reloadFavIcon.begin(icon); - return icon; - } - public async void reloadFavIcon(Gtk.Image? inIcon = null) - { Feed feed = DataBase.readOnly().read_feed(m_article.getFeedID()); - var icon = yield FavIconManager.get_default().getIcon(feed); - if(icon != null) - { - if(inIcon == null) - m_icon.pixbuf = icon; - else - inIcon.pixbuf = icon; - } - } + var favicon = FavIcon.for_feed(feed); + favicon.get_pixbuf.begin((obj, res) => { + var pixbuf = favicon.get_pixbuf.end(res); + if(pixbuf != null) + icon.pixbuf = pixbuf; + }); + favicon.pixbuf_changed.connect((feed, pixbuf) => { + if(pixbuf != null) + icon.pixbuf = pixbuf; + }); + return icon; + } private Gtk.Window getFeedIconWindow() { diff --git a/src/Widgets/FeedRow.vala b/src/Widgets/FeedRow.vala index 0a27024c..4eaf6a06 100644 --- a/src/Widgets/FeedRow.vala +++ b/src/Widgets/FeedRow.vala @@ -46,11 +46,6 @@ public class FeedReader.FeedRow : Gtk.ListBoxRow { m_icon = createFavIcon(); m_icon.margin_start = level * 24; - FavIconManager.get_default().ReloadFavIcon.connect(feed => { - if(m_feed.getFeedID() == feed.getFeedID()) - reloadFavIcon.begin(); - }); - m_label = new Gtk.Label(m_feed.getTitle()); m_label.set_size_request (0, rowhight); m_label.set_ellipsize (Pango.EllipsizeMode.END); @@ -156,26 +151,22 @@ public class FeedReader.FeedRow : Gtk.ListBoxRow { { var icon = new Gtk.Image.from_icon_name("feed-rss-symbolic", Gtk.IconSize.LARGE_TOOLBAR); icon.get_style_context().add_class("fr-sidebar-symbolic"); - reloadFavIcon.begin(icon); - return icon; - } - public async void reloadFavIcon(Gtk.Image? inIcon = null) - { - var icon = yield FavIconManager.get_default().getIcon(m_feed); - if(icon == null) - return; + var favicon = FavIcon.for_feed(m_feed); + favicon.get_pixbuf.begin((obj, res) => { + var pixbuf = favicon.get_pixbuf.end(res); + if(pixbuf != null) + { + icon.pixbuf = pixbuf; + m_icon.get_style_context().remove_class("fr-sidebar-symbolic"); + } + }); + favicon.pixbuf_changed.connect((feed, pixbuf) => { + icon.pixbuf = pixbuf; + icon.get_style_context().remove_class("fr-sidebar-symbolic"); + }); - if(inIcon == null) - { - m_icon.pixbuf = icon; - m_icon.get_style_context().remove_class("fr-sidebar-symbolic"); - } - else - { - inIcon.pixbuf = icon; - inIcon.get_style_context().remove_class("fr-sidebar-symbolic"); - } + return icon; } private Gtk.Window getFeedIconWindow() |