Files
ObsidianDragon/src/ui/windows/contacts_tab.h
DanS 4b8d80b2fc feat(contacts): animated avatars (GIF/WebP) with a Settings toggle
Animate contact avatars end to end:

- texture_loader gains LoadAnimatedRGBA: decodes an image into a downscaled
  RGBA frame sequence + per-frame durations — animated GIF via stb
  (stbi_load_gif_from_memory) and animated WebP via libwebp's WebPAnimDecoder;
  stills (and APNG, which stb reads as one image) return a single frame. Frames
  are box-downscaled (smaller cap for animations) to bound VRAM, capped at 300.
- The contacts avatar cache now holds a frame sequence; currentAvatarFrame()
  advances animated avatars by the ImGui clock and is used everywhere avatars
  draw (list, cards, table, grid, preview). When a live animated frame is drawn
  it flags the render loop (ConsumeContactsAvatarAnimation, clear-on-read) so
  main.cpp keeps producing frames while animation plays and idles when it stops
  or the contacts view is hidden.
- New animate_avatars setting (default on) + a Settings appearance toggle
  ("Animate avatars"); off shows the first frame only. currentAvatarFrame
  honors it. +i18n (8 langs, CJK subset rebuilt for 帧/播/첫).

Verified: a 3-frame GIF and a 3-frame animated WebP both decode to 3 frames
with correct 120ms delays through the exact libwebp/stb calls used here.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 11:11:06 -05:00

36 lines
1.1 KiB
C++

// DragonX Wallet - ImGui Edition
// Copyright 2024-2026 The Hush Developers
// Released under the GPLv3
#pragma once
namespace dragonx {
class App;
namespace ui {
/**
* @brief Render the Contacts tab (the address book, promoted out of Settings).
*
* Doubles as the future chat roster. Reads/writes the App-owned AddressBook
* (App::addressBook()). Renders inline in the main content area; the add/edit
* form is a modal popup layered over the tab.
*
* @param app Pointer to the app instance.
*/
void RenderContactsTab(App* app);
// True if an animated avatar frame was drawn since the previous call (clear-on-read). The main render
// loop uses this to keep drawing while an avatar animation plays, then idle when it stops.
bool ConsumeContactsAvatarAnimation();
// UI-sweep ONLY: open the revamped add/edit dialog on a seeded demo contact, in the given avatar
// mode (0 = badge, 1 = icon, 2 = image), so the sweep can capture the preview + avatar picker.
// Pair with ContactsSweepCloseDialog(). Do not use outside the sweep.
void ContactsSweepOpenEditDialog(int avatarMode);
void ContactsSweepCloseDialog();
} // namespace ui
} // namespace dragonx