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:
William Casarin
2025-08-04 13:38:27 -07:00
parent 54b86ee5a6
commit b94e715539
8 changed files with 206 additions and 73 deletions

View File

@@ -1,6 +1,6 @@
use bitflags::bitflags;
use egui::{emath::TSTransform, pos2, Color32, Rangef, Rect};
use notedeck::media::{MediaInfo, ViewMediaInfo};
use notedeck::media::{AnimationMode, MediaInfo, ViewMediaInfo};
use notedeck::{ImageType, Images};
bitflags! {
@@ -176,7 +176,12 @@ impl<'a> MediaViewer<'a> {
/// we have image layouts
fn first_image_rect(ui: &mut egui::Ui, media: &MediaInfo, images: &mut Images) -> Rect {
// fetch image texture
let Some(texture) = images.latest_texture(ui, &media.url, ImageType::Content(None)) else {
let Some(texture) = images.latest_texture(
ui,
&media.url,
ImageType::Content(None),
AnimationMode::NoAnimation,
) else {
tracing::error!("could not get latest texture in first_image_rect");
return Rect::ZERO;
};
@@ -206,7 +211,14 @@ impl<'a> MediaViewer<'a> {
let url = &info.url;
// fetch image texture
let Some(texture) = images.latest_texture(ui, url, ImageType::Content(None)) else {
// we want to continually redraw things in the gallery
let Some(texture) = images.latest_texture(
ui,
url,
ImageType::Content(None),
AnimationMode::Continuous { fps: None }, // media viewer has continuous rendering
) else {
continue;
};