notedeck

One damus client to rule them all
git clone git://jb55.com/notedeck
Log | Files | Refs | README | LICENSE

README.md (6599B)


      1 # NoteDeck UI Developer Documentation
      2 
      3 This document provides an in-depth overview of the `notedeck_ui` architecture, components, and guidelines for development.
      4 
      5 For a guide on some of our components, check out the [NoteDeck UI Component Guide](./components.md)
      6 
      7 ## Architecture
      8 
      9 The `notedeck_ui` crate is organized into modules that handle different aspects of the Nostr client UI:
     10 
     11 ```
     12 notedeck_ui
     13 ├── anim.rs           - Animation utilities and helpers
     14 ├── colors.rs         - Color constants and theme definitions
     15 ├── constants.rs      - UI constants (margins, sizes, etc.)
     16 ├── gif.rs            - GIF rendering and playback
     17 ├── icons.rs          - Icon rendering helpers
     18 ├── images.rs         - Image loading, caching, and display
     19 ├── lib.rs            - Main export and shared utilities
     20 ├── mention.rs        - Nostr mention component (@username)
     21 ├── note/             - Note display components
     22 │   ├── contents.rs   - Note content rendering
     23 │   ├── context.rs    - Note context menu
     24 │   ├── mod.rs        - Note view component
     25 │   ├── options.rs    - Note display options
     26 │   └── reply_description.rs - Reply metadata display
     27 ├── profile/          - Profile components
     28 │   ├── mod.rs        - Shared profile utilities
     29 │   ├── name.rs       - Profile name display
     30 │   ├── picture.rs    - Profile picture component
     31 │   └── preview.rs    - Profile hover preview
     32 ├── username.rs       - Username display component
     33 └── widgets.rs        - Generic widget helpers
     34 ```
     35 
     36 ## Core Components
     37 
     38 ### NoteView
     39 
     40 The `NoteView` component is the primary way to display Nostr notes. It handles rendering the note content, profile information, media, and interactive elements like replies and zaps.
     41 
     42 Key design aspects:
     43 - Stateful widget that maintains rendering state through EGUI's widget system
     44 - Configurable display options via `NoteOptions` bitflags
     45 - Support for different layouts (normal and wide)
     46 - Handles nested content (note previews, mentions, hashtags)
     47 
     48 ```rust
     49 // NoteView creation and display
     50 let mut note_view = NoteView::new(note_context, cur_acc, &note, options);
     51 note_view.show(ui); // Returns NoteResponse with action
     52 ```
     53 
     54 ### Note Actions
     55 
     56 The note components use a pattern where user interactions produce `NoteAction` enum values:
     57 
     58 ```rust
     59 pub enum NoteAction {
     60     Note(NoteId),              // Note was clicked
     61     Profile(Pubkey),           // Profile was clicked
     62     Reply(NoteId),             // Reply button clicked
     63     Quote(NoteId),             // Quote button clicked
     64     Hashtag(String),           // Hashtag was clicked
     65     Zap(ZapAction),            // Zap interaction
     66     Context(ContextSelection), // Context menu selection
     67 }
     68 ```
     69 
     70 Actions are propagated up from inner components to the parent UI, which can handle navigation and state changes.
     71 
     72 ### Media Handling
     73 
     74 The media system uses a cache and promise-based loading system:
     75 
     76 1. `MediaCache` stores loaded images and animations
     77 2. `fetch_img` retrieves images from disk or network
     78 3. `render_images` handles the loading states and display
     79 
     80 For GIFs, the system:
     81 1. Decodes frames using a background thread
     82 2. Sends frames via channels to the UI thread
     83 3. Manages animation timing for playback
     84 
     85 ## Design Patterns
     86 
     87 ### Widget Pattern
     88 
     89 Components implement the `egui::Widget` trait for integration with EGUI:
     90 
     91 ```rust
     92 impl egui::Widget for ProfilePic<'_, '_> {
     93     fn ui(self, ui: &mut egui::Ui) -> egui::Response {
     94         render_pfp(ui, self.cache, self.url, self.size, self.border)
     95     }
     96 }
     97 ```
     98 
     99 ### Builder Pattern
    100 
    101 Components often use a builder pattern for configuration:
    102 
    103 ```rust
    104 let view = NoteView::new(context, account, &note, options)
    105     .small_pfp(true)
    106     .wide(true)
    107     .actionbar(false);
    108 ```
    109 
    110 ### Animation Helper
    111 
    112 For interactive elements, the `AnimationHelper` provides standardized hover animations:
    113 
    114 ```rust
    115 let helper = AnimationHelper::new(ui, "animation_id", max_size);
    116 let current_size = helper.scale_1d_pos(min_size);
    117 ```
    118 
    119 ## Working with Images
    120 
    121 Images are handled through different types depending on their purpose:
    122 
    123 1. `ImageType::Profile` - For profile pictures (with automatic cropping and rounding)
    124 2. `ImageType::Content` - For general content images
    125 
    126 ```rust
    127 // Loading and displaying an image
    128 render_images(
    129     ui,
    130     img_cache,
    131     url,
    132     ImageType::Profile(128), // Size hint
    133     MediaCacheType::Image,   // Static image or GIF
    134     |ui| { /* show while loading */ },
    135     |ui, err| { /* show on error */ },
    136     |ui, url, img, gifs| { /* show successful load */ },
    137 );
    138 ```
    139 
    140 ## Performance Considerations
    141 
    142 1. **Image Caching**: Images are cached both in memory and on disk
    143 2. **Animation Optimization**: GIF frames are decoded in background threads
    144 3. **Render Profiling**: Critical paths use `#[profiling::function]` for tracing
    145 4. **Layout Reuse**: Components cache layout data to prevent recalculation
    146 
    147 ## Theming
    148 
    149 The UI adapts to light/dark mode through EGUI's visuals system:
    150 
    151 ```rust
    152 // Access current theme
    153 let color = ui.visuals().hyperlink_color;
    154 
    155 // Check theme mode
    156 if ui.visuals().dark_mode {
    157     // Use dark mode resources
    158 } else {
    159     // Use light mode resources
    160 }
    161 ```
    162 
    163 ## Debugging Tips
    164 
    165 1. **EGUI Inspector**: Use `ctx.debug_painter()` to visualize layout bounds
    166 2. **Trace Logging**: Enable trace logs to debug image loading and caching
    167 3. **Animation Debugging**: Set `ANIM_SPEED` to a lower value to slow animations for visual debugging
    168 4. **ID Collisions**: Use unique IDs for animations and state to prevent interaction bugs
    169 
    170 ## Common Patterns
    171 
    172 ### Hover Previews
    173 
    174 ```rust
    175 // For elements with hover previews
    176 let resp = ui.add(/* widget */);
    177 resp.on_hover_ui_at_pointer(|ui| {
    178     ui.set_max_width(300.0);
    179     ui.add(ProfilePreview::new(profile, img_cache));
    180 });
    181 ```
    182 
    183 ### Context Menus
    184 
    185 ```rust
    186 // For elements with context menus
    187 let resp = ui.add(/* widget */);
    188 resp.context_menu(|ui| {
    189     if ui.button("Menu Option").clicked() {
    190         // Handle selection
    191         ui.close_menu();
    192     }
    193 });
    194 ```
    195 
    196 ## Contributing Guidelines
    197 
    198 When contributing to `notedeck_ui`:
    199 
    200 1. **Widget Consistency**: Follow established patterns for new widgets
    201 2. **Option Naming**: Keep option names consistent (has_X/set_X pairs)
    202 3. **Performance**: Add profiling annotations to expensive operations
    203 4. **Error Handling**: Propagate errors up rather than handling them directly in UI components
    204 5. **Documentation**: Document public APIs and components with examples
    205 6. **Theme Support**: Ensure components work in both light and dark mode