FeedTheMonkey/src/preferences_dialog.rs
Jeena fda441bebd feature: cache article images for offline reading
After fetching articles, all remote images referenced in article content
are downloaded to ~/.local/share/net.jeena.FeedTheMonkey/images/ and
their src attributes rewritten to file:// URIs. Subsequent loads of the
same article (including from the cache on the next startup) display
images without a network connection.

Metered-connection awareness: image caching is skipped automatically
when GIO reports the network connection as metered, regardless of the
preference setting.

A "Cache Images" toggle in Preferences lets the user disable caching
entirely (stored in the cache-images GSettings key).

After each refresh, images no longer referenced by any article in the
current unread list are deleted from the cache directory to prevent
unbounded disk growth.
2026-03-21 01:19:49 +00:00

80 lines
2.6 KiB
Rust

use gtk4::prelude::*;
use gtk4::subclass::prelude::*;
use gtk4::{gio, glib};
glib::wrapper! {
pub struct PreferencesDialog(ObjectSubclass<imp::PreferencesDialog>)
@extends libadwaita::Dialog, gtk4::Widget,
@implements gtk4::Accessible, gtk4::Buildable, gtk4::ConstraintTarget;
}
impl PreferencesDialog {
pub fn new() -> Self {
glib::Object::builder().build()
}
}
pub mod imp {
use super::*;
use gtk4::CompositeTemplate;
use libadwaita::subclass::prelude::*;
#[derive(CompositeTemplate, Default)]
#[template(resource = "/net/jeena/FeedTheMonkey/ui/preferences_dialog.ui")]
pub struct PreferencesDialog {
#[template_child]
pub cache_images_row: TemplateChild<libadwaita::SwitchRow>,
#[template_child]
pub filters_text_view: TemplateChild<gtk4::TextView>,
}
#[glib::object_subclass]
impl ObjectSubclass for PreferencesDialog {
const NAME: &'static str = "PreferencesDialog";
type Type = super::PreferencesDialog;
type ParentType = libadwaita::Dialog;
fn class_init(klass: &mut Self::Class) {
klass.bind_template();
}
fn instance_init(obj: &glib::subclass::InitializingObject<Self>) {
obj.init_template();
}
}
impl ObjectImpl for PreferencesDialog {
fn constructed(&self) {
self.parent_constructed();
let settings = gio::Settings::new("net.jeena.FeedTheMonkey");
// Cache images switch
self.cache_images_row.set_active(settings.boolean("cache-images"));
let s = settings.clone();
self.cache_images_row.connect_active_notify(move |row| {
s.set_boolean("cache-images", row.is_active()).ok();
});
// Content filters text view
self.filters_text_view.buffer().set_text(&settings.string("content-filters"));
let obj_weak = self.obj().downgrade();
self.filters_text_view.buffer().connect_changed(move |_| {
if let Some(obj) = obj_weak.upgrade() {
obj.imp().save_filters();
}
});
}
}
impl PreferencesDialog {
fn save_filters(&self) {
let buf = self.filters_text_view.buffer();
let text = buf.text(&buf.start_iter(), &buf.end_iter(), false);
let settings = gio::Settings::new("net.jeena.FeedTheMonkey");
settings.set_string("content-filters", &text).ok();
}
}
impl WidgetImpl for PreferencesDialog {}
impl AdwDialogImpl for PreferencesDialog {}
}