- Added `SoftKeyboardContext` enum and support for calculating keyboard insets from both virtual and platform sources - Updated `AppContext` to provide `soft_keyboard_rect` for determining visible keyboard area - Adjusted UI rendering to shift content when input boxes intersect with the soft keyboard, preventing overlap - Modified `MainActivity` and Android manifest to use `windowSoftInputMode="adjustResize"` and updated window inset handling - Introduced helper functions (`include_input`, `input_rect`, `clear_input_rect`) in `notedeck_ui` for tracking focused input boxes - Fixed Android JNI keyboard height reporting to clamp negative values Together, these changes allow the app to correctly detect and respond to soft keyboard visibility on Android, ensuring input fields remain accessible when typing. Fixes: https://github.com/damus-io/notedeck/issues/946 Fixes: https://github.com/damus-io/notedeck/issues/1043
NoteDeck UI
UI component library for NoteDeck - a Nostr client built with EGUI.
Overview
The notedeck_ui crate provides a set of reusable UI components for building a Nostr client. It offers consistent styling, behavior, and rendering of Nostr-specific elements like notes, profiles, mentions, and media content.
This library is built on top of egui, a simple, fast, and highly portable immediate mode GUI library for Rust.
Features
- 📝 Note display with rich content, media, and interactions
- 👤 Profile components (display name, pictures, banners)
- 🔗 Mention system with hover previews
- 🖼️ Image handling with caching and lazy loading
- 📺 GIF playback support
- 💸 Zap interactions (Bitcoin Lightning tips)
- 🎨 Theming and consistent styling
Components
Notes
The NoteView widget is the core component for displaying Nostr notes:
// Example: Render a note
let mut note_view = NoteView::new(
note_context,
current_account,
¬e,
NoteOptions::default()
);
ui.add(&mut note_view);
NoteView supports various display options:
// Create a preview style note
note_view
.preview_style() // Apply preview styling
.textmode(true) // Use text-only mode
.actionbar(false) // Hide action bar
.small_pfp(true) // Use small profile picture
.note_previews(false) // Disable nested note previews
.show(ui);
Profiles
Profile components include profile pictures, banners, and display names:
// Display a profile picture
ui.add(ProfilePic::new(images_cache, profile_picture_url).size(48.0));
// Display a profile preview
ui.add(ProfilePreview::new(profile_record, images_cache));
Mentions
The mention component links to user profiles:
// Display a mention with hover preview
let mention_response = Mention::new(ndb, img_cache, txn, pubkey)
.size(16.0) // Set text size
.selectable(true) // Allow selection
.show(ui);
// Handle click actions
if let Some(action) = mention_response.inner {
// Handle profile navigation
}
Media
Support for images, GIFs, and other media types:
// Render an image
render_images(
ui,
img_cache,
image_url,
ImageType::Content,
cache_type,
on_loading_callback,
on_error_callback,
on_success_callback
);
Styling
The UI components adapt to the current theme (light/dark mode) and use consistent styling defined in the colors.rs module:
// Color constants
pub const ALMOST_WHITE: Color32 = Color32::from_rgb(0xFA, 0xFA, 0xFA);
pub const MID_GRAY: Color32 = Color32::from_rgb(0xbd, 0xbd, 0xbd);
pub const PINK: Color32 = Color32::from_rgb(0xE4, 0x5A, 0xC9);
pub const TEAL: Color32 = Color32::from_rgb(0x77, 0xDC, 0xE1);
Dependencies
This crate depends on:
egui- Core UI libraryegui_extras- Additional widgets and functionalityehttp- HTTP client for fetching contentnostrdb- Nostr database and typesenostr- Nostr protocol implementationimage- Image processing librarypoll-promise- Async promise handlingtokio- Async runtime