ui: add AnimationMode to control GIF rendering behavior
Introduces an `AnimationMode` enum with `Reactive`, `Continuous`, and `NoAnimation` variants to allow fine-grained control over GIF playback across the UI. This supports performance optimizations and accessibility features, such as disabling animations when requested. - Plumbs AnimationMode through image rendering paths - Replaces hardcoded gif frame logic with reusable `process_gif_frame` - Supports customizable FPS in Continuous mode - Enables global animation opt-out via `NoteOptions::NoAnimations` - Applies mode-specific logic in profile pictures, posts, media carousels, and viewer Animation behavior by context ----------------------------- - Profile pictures: Reactive (render only on interaction/activity) - PostView: NoAnimation if disabled in NoteOptions, else Continuous (uncapped) - Media carousels: NoAnimation or Continuous (capped at 24fps) - Viewer/gallery: Always Continuous (full animation) In the future, we can customize these by power settings. Signed-off-by: William Casarin <jb55@jb55.com>
This commit is contained in:
@@ -3,6 +3,7 @@ use egui::{vec2, InnerResponse, Sense, Stroke, TextureHandle};
|
||||
use notedeck::get_render_state;
|
||||
use notedeck::media::gif::ensure_latest_texture;
|
||||
use notedeck::media::images::{fetch_no_pfp_promise, ImageType};
|
||||
use notedeck::media::AnimationMode;
|
||||
use notedeck::MediaAction;
|
||||
use notedeck::{show_one_error_message, supported_mime_hosted_at_url, Images};
|
||||
|
||||
@@ -12,12 +13,21 @@ pub struct ProfilePic<'cache, 'url> {
|
||||
size: f32,
|
||||
sense: Sense,
|
||||
border: Option<Stroke>,
|
||||
animation_mode: AnimationMode,
|
||||
pub action: Option<MediaAction>,
|
||||
}
|
||||
|
||||
impl egui::Widget for &mut ProfilePic<'_, '_> {
|
||||
fn ui(self, ui: &mut egui::Ui) -> egui::Response {
|
||||
let inner = render_pfp(ui, self.cache, self.url, self.size, self.border, self.sense);
|
||||
let inner = render_pfp(
|
||||
ui,
|
||||
self.cache,
|
||||
self.url,
|
||||
self.size,
|
||||
self.border,
|
||||
self.sense,
|
||||
self.animation_mode,
|
||||
);
|
||||
|
||||
self.action = inner.inner;
|
||||
|
||||
@@ -35,6 +45,7 @@ impl<'cache, 'url> ProfilePic<'cache, 'url> {
|
||||
sense,
|
||||
url,
|
||||
size,
|
||||
animation_mode: AnimationMode::Reactive,
|
||||
border: None,
|
||||
action: None,
|
||||
}
|
||||
@@ -45,6 +56,11 @@ impl<'cache, 'url> ProfilePic<'cache, 'url> {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn animation_mode(mut self, mode: AnimationMode) -> Self {
|
||||
self.animation_mode = mode;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn border_stroke(ui: &egui::Ui) -> Stroke {
|
||||
Stroke::new(4.0, ui.visuals().panel_fill)
|
||||
}
|
||||
@@ -109,6 +125,7 @@ fn render_pfp(
|
||||
ui_size: f32,
|
||||
border: Option<Stroke>,
|
||||
sense: Sense,
|
||||
animation_mode: AnimationMode,
|
||||
) -> InnerResponse<Option<MediaAction>> {
|
||||
// We will want to downsample these so it's not blurry on hi res displays
|
||||
let img_size = 128u32;
|
||||
@@ -141,7 +158,8 @@ fn render_pfp(
|
||||
)
|
||||
}
|
||||
notedeck::TextureState::Loaded(textured_image) => {
|
||||
let texture_handle = ensure_latest_texture(ui, url, cur_state.gifs, textured_image);
|
||||
let texture_handle =
|
||||
ensure_latest_texture(ui, url, cur_state.gifs, textured_image, animation_mode);
|
||||
|
||||
egui::InnerResponse::new(None, pfp_image(ui, &texture_handle, ui_size, border, sense))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user