Files
notedeck/crates/notedeck_ui/src/note/options.rs
T
William Casarin b94e715539 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>
2025-08-04 13:41:24 -07:00

70 lines
2.1 KiB
Rust

use crate::ProfilePic;
use bitflags::bitflags;
bitflags! {
// Attributes can be applied to flags types
#[repr(transparent)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct NoteOptions: u64 {
const ActionBar = 1 << 0;
const HasNotePreviews = 1 << 1;
const SmallPfp = 1 << 2;
const MediumPfp = 1 << 3;
const Wide = 1 << 4;
const SelectableText = 1 << 5;
const Textmode = 1 << 6;
const OptionsButton = 1 << 7;
const HideMedia = 1 << 8;
/// Scramble text so that its not distracting during development
const ScrambleText = 1 << 9;
/// Is this a note preview?
const IsPreview = 1 << 10;
/// Is the content truncated? If the length is over a certain size it
/// will end with a ... and a "Show more" button.
const Truncate = 1 << 11;
/// Show note's client in the note content
const ClientName = 1 << 12;
const RepliesNewestFirst = 1 << 13;
/// Show note's full created at date at the bottom
const FullCreatedDate = 1 << 14;
/// Note has a framed border
const Framed = 1 << 15;
/// Note has an unread reply indicator
const UnreadIndicator = 1 << 16;
/// no animation override (accessibility)
const NoAnimations = 1 << 17;
}
}
impl Default for NoteOptions {
fn default() -> NoteOptions {
NoteOptions::OptionsButton
| NoteOptions::HasNotePreviews
| NoteOptions::ActionBar
| NoteOptions::Truncate
}
}
impl NoteOptions {
pub fn new(is_universe_timeline: bool) -> Self {
let mut options = NoteOptions::default();
options.set(NoteOptions::HideMedia, is_universe_timeline);
options
}
pub fn pfp_size(&self) -> i8 {
if self.contains(NoteOptions::SmallPfp) {
ProfilePic::small_size()
} else if self.contains(NoteOptions::MediumPfp) {
ProfilePic::medium_size()
} else {
ProfilePic::default_size()
}
}
}