introduce View and Previews traits
In this commit we refactor the preview mechanism, and switch to responsive views by default. To create a preview, your view now has to implement the Preview trait. This is very similar to SwiftUI's preview mechanism. Signed-off-by: William Casarin <jb55@jb55.com>
This commit is contained in:
@@ -1,74 +1,142 @@
|
|||||||
use crate::app_style::NotedeckTextStyle;
|
use crate::app_style::NotedeckTextStyle;
|
||||||
use crate::key_parsing::{perform_key_retrieval, LoginError};
|
use crate::key_parsing::{perform_key_retrieval, LoginError};
|
||||||
use crate::login_manager::LoginManager;
|
use crate::login_manager::LoginManager;
|
||||||
|
use crate::ui;
|
||||||
|
use crate::ui::{Preview, View};
|
||||||
use egui::{
|
use egui::{
|
||||||
Align, Align2, Button, Color32, Frame, Id, LayerId, Margin, Pos2, Rect, RichText, Rounding, Ui,
|
Align, Align2, Button, Color32, Frame, Id, LayerId, Margin, Pos2, Rect, RichText, Rounding, Ui,
|
||||||
Vec2, Window,
|
Vec2, Window,
|
||||||
};
|
};
|
||||||
use egui::{Image, TextBuffer, TextEdit};
|
use egui::{Image, TextBuffer, TextEdit};
|
||||||
|
|
||||||
pub struct DesktopAccountLoginView<'a> {
|
pub struct AccountLoginView<'a> {
|
||||||
ctx: &'a egui::Context,
|
|
||||||
manager: &'a mut LoginManager,
|
manager: &'a mut LoginManager,
|
||||||
generate_y_intercept: Option<f32>,
|
generate_y_intercept: Option<f32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> DesktopAccountLoginView<'a> {
|
impl<'a> View for AccountLoginView<'a> {
|
||||||
pub fn new(ctx: &'a egui::Context, manager: &'a mut LoginManager) -> Self {
|
fn ui(&mut self, ui: &mut egui::Ui) {
|
||||||
DesktopAccountLoginView {
|
if ui::is_mobile(ui.ctx()) {
|
||||||
ctx,
|
self.show_mobile(ui);
|
||||||
|
} else {
|
||||||
|
self.show(ui);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> AccountLoginView<'a> {
|
||||||
|
pub fn new(manager: &'a mut LoginManager) -> Self {
|
||||||
|
AccountLoginView {
|
||||||
manager,
|
manager,
|
||||||
generate_y_intercept: None,
|
generate_y_intercept: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn panel(&mut self) {
|
fn show(&mut self, ui: &mut egui::Ui) -> egui::Response {
|
||||||
let frame = egui::CentralPanel::default();
|
let screen_width = ui.ctx().screen_rect().max.x;
|
||||||
|
let screen_height = ui.ctx().screen_rect().max.y;
|
||||||
|
|
||||||
let screen_width = self.ctx.screen_rect().max.x;
|
let title_layer = LayerId::new(egui::Order::Background, Id::new("Title layer"));
|
||||||
let screen_height = self.ctx.screen_rect().max.y;
|
|
||||||
|
|
||||||
frame.show(self.ctx, |ui| {
|
let mut top_panel_height: Option<f32> = None;
|
||||||
let title_layer = LayerId::new(egui::Order::Background, Id::new("Title layer"));
|
ui.with_layer_id(title_layer, |ui| {
|
||||||
|
egui::TopBottomPanel::top("Top")
|
||||||
let mut top_panel_height: Option<f32> = None;
|
|
||||||
ui.with_layer_id(title_layer, |ui| {
|
|
||||||
egui::TopBottomPanel::top("Top")
|
|
||||||
.resizable(false)
|
|
||||||
.default_height(340.0)
|
|
||||||
.frame(Frame::none())
|
|
||||||
.show_separator_line(false)
|
|
||||||
.show_inside(ui, |ui| {
|
|
||||||
top_panel_height = Some(ui.available_rect_before_wrap().bottom());
|
|
||||||
self.top_title_area(ui);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
egui::TopBottomPanel::bottom("Bottom")
|
|
||||||
.resizable(false)
|
.resizable(false)
|
||||||
|
.default_height(340.0)
|
||||||
.frame(Frame::none())
|
.frame(Frame::none())
|
||||||
.show_separator_line(false)
|
.show_separator_line(false)
|
||||||
.show_inside(ui, |ui| {
|
.show_inside(ui, |ui| {
|
||||||
self.window(ui, top_panel_height.unwrap_or(0.0));
|
top_panel_height = Some(ui.available_rect_before_wrap().bottom());
|
||||||
|
self.top_title_area(ui);
|
||||||
});
|
});
|
||||||
|
|
||||||
let top_rect = Rect {
|
|
||||||
min: Pos2::ZERO,
|
|
||||||
max: Pos2::new(
|
|
||||||
screen_width,
|
|
||||||
self.generate_y_intercept.unwrap_or(screen_height * 0.5),
|
|
||||||
),
|
|
||||||
};
|
|
||||||
|
|
||||||
let top_background_color = ui.visuals().noninteractive().bg_fill;
|
|
||||||
ui.painter_at(top_rect)
|
|
||||||
.with_layer_id(LayerId::background())
|
|
||||||
.rect_filled(top_rect, Rounding::ZERO, top_background_color);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
egui::TopBottomPanel::bottom("Bottom")
|
||||||
|
.resizable(false)
|
||||||
|
.frame(Frame::none())
|
||||||
|
.show_separator_line(false)
|
||||||
|
.show_inside(ui, |ui| {
|
||||||
|
self.window(ui, top_panel_height.unwrap_or(0.0));
|
||||||
|
});
|
||||||
|
|
||||||
|
let top_rect = Rect {
|
||||||
|
min: Pos2::ZERO,
|
||||||
|
max: Pos2::new(
|
||||||
|
screen_width,
|
||||||
|
self.generate_y_intercept.unwrap_or(screen_height * 0.5),
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
let top_background_color = ui.visuals().noninteractive().bg_fill;
|
||||||
|
ui.painter_at(top_rect)
|
||||||
|
.with_layer_id(LayerId::background())
|
||||||
|
.rect_filled(top_rect, Rounding::ZERO, top_background_color);
|
||||||
|
|
||||||
|
egui::CentralPanel::default()
|
||||||
|
.show(ui.ctx(), |ui: &mut egui::Ui| {})
|
||||||
|
.response
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mobile_ui(&mut self, ui: &mut egui::Ui) -> egui::Response {
|
||||||
|
ui.vertical(|ui| {
|
||||||
|
ui.vertical_centered(|ui| {
|
||||||
|
ui.add(logo_unformatted().max_width(256.0));
|
||||||
|
ui.add_space(64.0);
|
||||||
|
ui.label(login_info_text());
|
||||||
|
ui.add_space(32.0);
|
||||||
|
ui.label(login_title_text());
|
||||||
|
});
|
||||||
|
|
||||||
|
ui.horizontal(|ui| {
|
||||||
|
ui.label(login_textedit_info_text());
|
||||||
|
});
|
||||||
|
|
||||||
|
ui.vertical_centered_justified(|ui| {
|
||||||
|
ui.add(login_textedit(&mut self.manager.login_key));
|
||||||
|
|
||||||
|
if ui.add(login_button()).clicked() {
|
||||||
|
self.manager.promise = Some(perform_key_retrieval(&self.manager.login_key));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ui.horizontal(|ui| {
|
||||||
|
ui.label(
|
||||||
|
RichText::new("New to Nostr?")
|
||||||
|
.color(ui.style().visuals.noninteractive().fg_stroke.color)
|
||||||
|
.text_style(NotedeckTextStyle::Body.text_style()),
|
||||||
|
);
|
||||||
|
|
||||||
|
if ui
|
||||||
|
.add(Button::new(RichText::new("Create Account")).frame(false))
|
||||||
|
.clicked()
|
||||||
|
{
|
||||||
|
// TODO: navigate to 'create account' screen
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.response
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn show_mobile(&mut self, ui: &mut egui::Ui) -> egui::Response {
|
||||||
|
egui::CentralPanel::default()
|
||||||
|
.show(ui.ctx(), |_| {
|
||||||
|
Window::new("Login")
|
||||||
|
.movable(true)
|
||||||
|
.constrain(true)
|
||||||
|
.collapsible(false)
|
||||||
|
.drag_to_scroll(false)
|
||||||
|
.title_bar(false)
|
||||||
|
.resizable(false)
|
||||||
|
.anchor(Align2::CENTER_CENTER, [0.0, 0.0])
|
||||||
|
.frame(Frame::central_panel(&ui.ctx().style()))
|
||||||
|
.max_width(ui.ctx().screen_rect().width() - 32.0) // margin
|
||||||
|
.show(ui.ctx(), |ui| self.mobile_ui(ui));
|
||||||
|
})
|
||||||
|
.response
|
||||||
}
|
}
|
||||||
|
|
||||||
fn window(&mut self, ui: &mut Ui, top_panel_height: f32) {
|
fn window(&mut self, ui: &mut Ui, top_panel_height: f32) {
|
||||||
let needed_height_over_top = (self.ctx.screen_rect().bottom() / 2.0) - 230.0;
|
let needed_height_over_top = (ui.ctx().screen_rect().bottom() / 2.0) - 230.0;
|
||||||
let y_offset = if top_panel_height > needed_height_over_top {
|
let y_offset = if top_panel_height > needed_height_over_top {
|
||||||
top_panel_height - needed_height_over_top
|
top_panel_height - needed_height_over_top
|
||||||
} else {
|
} else {
|
||||||
@@ -274,67 +342,21 @@ fn login_textedit(text: &mut dyn TextBuffer) -> TextEdit {
|
|||||||
.margin(Margin::same(12.0))
|
.margin(Margin::same(12.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct MobileAccountLoginView<'a> {
|
pub struct AccountLoginPreview {
|
||||||
ctx: &'a egui::Context,
|
manager: LoginManager,
|
||||||
manager: &'a mut LoginManager,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> MobileAccountLoginView<'a> {
|
impl View for AccountLoginPreview {
|
||||||
pub fn new(ctx: &'a egui::Context, manager: &'a mut LoginManager) -> Self {
|
fn ui(&mut self, ui: &mut egui::Ui) {
|
||||||
MobileAccountLoginView { ctx, manager }
|
AccountLoginView::new(&mut self.manager).ui(ui);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
pub fn panel(&mut self) {
|
|
||||||
let frame = egui::CentralPanel::default();
|
impl<'a> Preview for AccountLoginView<'a> {
|
||||||
|
type Prev = AccountLoginPreview;
|
||||||
frame.show(self.ctx, |_| {
|
|
||||||
Window::new("Login")
|
fn preview() -> Self::Prev {
|
||||||
.movable(true)
|
let manager = LoginManager::new();
|
||||||
.constrain(true)
|
AccountLoginPreview { manager }
|
||||||
.collapsible(false)
|
|
||||||
.drag_to_scroll(false)
|
|
||||||
.title_bar(false)
|
|
||||||
.resizable(false)
|
|
||||||
.anchor(Align2::CENTER_CENTER, [0.0, 0.0])
|
|
||||||
.frame(Frame::central_panel(&self.ctx.style()))
|
|
||||||
.max_width(self.ctx.screen_rect().width() - 32.0) // margin
|
|
||||||
.show(self.ctx, |ui| {
|
|
||||||
ui.vertical_centered(|ui| {
|
|
||||||
ui.add(logo_unformatted().max_width(256.0));
|
|
||||||
ui.add_space(64.0);
|
|
||||||
ui.label(login_info_text());
|
|
||||||
ui.add_space(32.0);
|
|
||||||
ui.label(login_title_text());
|
|
||||||
});
|
|
||||||
|
|
||||||
ui.horizontal(|ui| {
|
|
||||||
ui.label(login_textedit_info_text());
|
|
||||||
});
|
|
||||||
|
|
||||||
ui.vertical_centered_justified(|ui| {
|
|
||||||
ui.add(login_textedit(&mut self.manager.login_key));
|
|
||||||
|
|
||||||
if ui.add(login_button()).clicked() {
|
|
||||||
self.manager.promise =
|
|
||||||
Some(perform_key_retrieval(&self.manager.login_key));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
ui.horizontal(|ui| {
|
|
||||||
ui.label(
|
|
||||||
RichText::new("New to Nostr?")
|
|
||||||
.color(ui.style().visuals.noninteractive().fg_stroke.color)
|
|
||||||
.text_style(NotedeckTextStyle::Body.text_style()),
|
|
||||||
);
|
|
||||||
|
|
||||||
if ui
|
|
||||||
.add(Button::new(RichText::new("Create Account")).frame(false))
|
|
||||||
.clicked()
|
|
||||||
{
|
|
||||||
// TODO: navigate to 'create account' screen
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ use crate::imgcache::ImageCache;
|
|||||||
use crate::notecache::NoteCache;
|
use crate::notecache::NoteCache;
|
||||||
use crate::timeline;
|
use crate::timeline;
|
||||||
use crate::ui;
|
use crate::ui;
|
||||||
|
use crate::ui::is_mobile;
|
||||||
use crate::Result;
|
use crate::Result;
|
||||||
use egui::containers::scroll_area::ScrollBarVisibility;
|
use egui::containers::scroll_area::ScrollBarVisibility;
|
||||||
|
|
||||||
@@ -87,12 +88,6 @@ pub struct Damus {
|
|||||||
frame_history: crate::frame_history::FrameHistory,
|
frame_history: crate::frame_history::FrameHistory,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_mobile(ctx: &egui::Context) -> bool {
|
|
||||||
//true
|
|
||||||
let screen_size = ctx.screen_rect().size();
|
|
||||||
screen_size.x < 550.0
|
|
||||||
}
|
|
||||||
|
|
||||||
fn relay_setup(pool: &mut RelayPool, ctx: &egui::Context) {
|
fn relay_setup(pool: &mut RelayPool, ctx: &egui::Context) {
|
||||||
let ctx = ctx.clone();
|
let ctx = ctx.clone();
|
||||||
let wakeup = move || {
|
let wakeup = move || {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use crate::app::is_mobile;
|
|
||||||
use crate::app_style::{create_text_styles, dark_mode, desktop_font_size, mobile_font_size};
|
use crate::app_style::{create_text_styles, dark_mode, desktop_font_size, mobile_font_size};
|
||||||
use crate::fonts::setup_fonts;
|
use crate::fonts::setup_fonts;
|
||||||
|
use crate::ui::is_mobile;
|
||||||
use eframe::NativeOptions;
|
use eframe::NativeOptions;
|
||||||
|
|
||||||
pub const UI_SCALE_FACTOR: f32 = 0.2;
|
pub const UI_SCALE_FACTOR: f32 = 0.2;
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ mod result;
|
|||||||
mod time;
|
mod time;
|
||||||
mod timecache;
|
mod timecache;
|
||||||
mod timeline;
|
mod timeline;
|
||||||
mod ui;
|
pub mod ui;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
|||||||
@@ -1,52 +1,52 @@
|
|||||||
use crate::relay_pool_manager::{RelayPoolManager, RelayStatus};
|
use crate::relay_pool_manager::{RelayPoolManager, RelayStatus};
|
||||||
|
use crate::ui::{Preview, View};
|
||||||
use egui::{Align, Button, Frame, Layout, Margin, Rgba, RichText, Rounding, Ui, Vec2};
|
use egui::{Align, Button, Frame, Layout, Margin, Rgba, RichText, Rounding, Ui, Vec2};
|
||||||
|
|
||||||
use crate::app_style::NotedeckTextStyle;
|
use crate::app_style::NotedeckTextStyle;
|
||||||
|
use enostr::RelayPool;
|
||||||
|
|
||||||
pub struct RelayView<'a> {
|
pub struct RelayView<'a> {
|
||||||
ctx: &'a egui::Context,
|
|
||||||
manager: RelayPoolManager<'a>,
|
manager: RelayPoolManager<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> RelayView<'a> {
|
impl<'a> View for RelayView<'a> {
|
||||||
pub fn new(ctx: &'a egui::Context, manager: RelayPoolManager<'a>) -> Self {
|
fn ui(&mut self, ui: &mut egui::Ui) {
|
||||||
RelayView { ctx, manager }
|
ui.add_space(24.0);
|
||||||
}
|
|
||||||
|
|
||||||
pub fn panel(&'a mut self) {
|
ui.horizontal(|ui| {
|
||||||
let mut indices_to_remove: Option<Vec<usize>> = None;
|
ui.with_layout(Layout::left_to_right(Align::Center), |ui| {
|
||||||
|
ui.label(
|
||||||
egui::CentralPanel::default().show(self.ctx, |ui| {
|
RichText::new("Relays").text_style(NotedeckTextStyle::Heading2.text_style()),
|
||||||
ui.add_space(24.0);
|
);
|
||||||
|
|
||||||
ui.horizontal(|ui| {
|
|
||||||
ui.with_layout(Layout::left_to_right(Align::Center), |ui| {
|
|
||||||
ui.label(
|
|
||||||
RichText::new("Relays")
|
|
||||||
.text_style(NotedeckTextStyle::Heading2.text_style()),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
ui.with_layout(Layout::right_to_left(Align::Center), |ui| {
|
|
||||||
if ui.add(add_relay_button()).clicked() {
|
|
||||||
// TODO: navigate to 'add relay view'
|
|
||||||
};
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
ui.add_space(8.0);
|
ui.with_layout(Layout::right_to_left(Align::Center), |ui| {
|
||||||
|
if ui.add(add_relay_button()).clicked() {
|
||||||
egui::ScrollArea::vertical()
|
// TODO: navigate to 'add relay view'
|
||||||
.scroll_bar_visibility(egui::scroll_area::ScrollBarVisibility::AlwaysHidden)
|
};
|
||||||
.auto_shrink([false; 2])
|
});
|
||||||
.show(ui, |ui| {
|
|
||||||
indices_to_remove = self.show_relays(ui);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if let Some(indices) = indices_to_remove {
|
ui.add_space(8.0);
|
||||||
self.manager.remove_relays(indices);
|
|
||||||
}
|
egui::ScrollArea::vertical()
|
||||||
|
.scroll_bar_visibility(egui::scroll_area::ScrollBarVisibility::AlwaysHidden)
|
||||||
|
.auto_shrink([false; 2])
|
||||||
|
.show(ui, |ui| {
|
||||||
|
if let Some(indices) = self.show_relays(ui) {
|
||||||
|
self.manager.remove_relays(indices);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> RelayView<'a> {
|
||||||
|
pub fn new(manager: RelayPoolManager<'a>) -> Self {
|
||||||
|
RelayView { manager }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn panel(&mut self, ui: &mut egui::Ui) {
|
||||||
|
egui::CentralPanel::default().show(ui.ctx(), |ui| self.ui(ui));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Show the current relays, and returns the indices of relays the user requested to delete
|
/// Show the current relays, and returns the indices of relays the user requested to delete
|
||||||
@@ -169,3 +169,44 @@ fn get_connection_icon(status: &RelayStatus) -> egui::Image<'static> {
|
|||||||
|
|
||||||
egui::Image::new(img_data)
|
egui::Image::new(img_data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PREVIEWS
|
||||||
|
|
||||||
|
pub struct RelayViewPreview {
|
||||||
|
pool: RelayPool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused_must_use)]
|
||||||
|
impl RelayViewPreview {
|
||||||
|
fn new() -> Self {
|
||||||
|
let mut pool = RelayPool::new();
|
||||||
|
let wakeup = move || {};
|
||||||
|
|
||||||
|
pool.add_url("wss://relay.damus.io".to_string(), wakeup);
|
||||||
|
pool.add_url("wss://eden.nostr.land".to_string(), wakeup);
|
||||||
|
pool.add_url("wss://nostr.wine".to_string(), wakeup);
|
||||||
|
pool.add_url("wss://nos.lol".to_string(), wakeup);
|
||||||
|
pool.add_url("wss://test_relay_url_long_00000000000000000000000000000000000000000000000000000000000000000000000000000000000".to_string(), wakeup);
|
||||||
|
|
||||||
|
for _ in 0..20 {
|
||||||
|
pool.add_url("tmp".to_string(), wakeup);
|
||||||
|
}
|
||||||
|
|
||||||
|
RelayViewPreview { pool }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl View for RelayViewPreview {
|
||||||
|
fn ui(&mut self, ui: &mut egui::Ui) {
|
||||||
|
self.pool.try_recv();
|
||||||
|
RelayView::new(RelayPoolManager::new(&mut self.pool)).ui(ui)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Preview for RelayView<'a> {
|
||||||
|
type Prev = RelayViewPreview;
|
||||||
|
|
||||||
|
fn preview() -> Self::Prev {
|
||||||
|
RelayViewPreview::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,11 +1,17 @@
|
|||||||
pub mod note;
|
pub mod note;
|
||||||
|
pub mod preview;
|
||||||
pub mod username;
|
pub mod username;
|
||||||
|
|
||||||
pub use note::Note;
|
pub use note::Note;
|
||||||
|
pub use preview::{Preview, PreviewApp};
|
||||||
pub use username::Username;
|
pub use username::Username;
|
||||||
|
|
||||||
use egui::Margin;
|
use egui::Margin;
|
||||||
|
|
||||||
|
pub trait View {
|
||||||
|
fn ui(&mut self, ui: &mut egui::Ui);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn padding<R>(
|
pub fn padding<R>(
|
||||||
amount: impl Into<Margin>,
|
amount: impl Into<Margin>,
|
||||||
ui: &mut egui::Ui,
|
ui: &mut egui::Ui,
|
||||||
@@ -15,3 +21,9 @@ pub fn padding<R>(
|
|||||||
.inner_margin(amount)
|
.inner_margin(amount)
|
||||||
.show(ui, add_contents)
|
.show(ui, add_contents)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_mobile(ctx: &egui::Context) -> bool {
|
||||||
|
//true
|
||||||
|
let screen_size = ctx.screen_rect().size();
|
||||||
|
screen_size.x < 550.0
|
||||||
|
}
|
||||||
|
|||||||
33
src/ui/preview.rs
Normal file
33
src/ui/preview.rs
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
use crate::ui::View;
|
||||||
|
|
||||||
|
pub trait Preview {
|
||||||
|
type Prev: View;
|
||||||
|
|
||||||
|
fn preview() -> Self::Prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PreviewApp {
|
||||||
|
view: Box<dyn View>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<V> From<V> for PreviewApp
|
||||||
|
where
|
||||||
|
V: View + 'static,
|
||||||
|
{
|
||||||
|
fn from(v: V) -> Self {
|
||||||
|
PreviewApp::new(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PreviewApp {
|
||||||
|
pub fn new(view: impl View + 'static) -> PreviewApp {
|
||||||
|
let view = Box::new(view);
|
||||||
|
Self { view }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl eframe::App for PreviewApp {
|
||||||
|
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
|
||||||
|
egui::CentralPanel::default().show(ctx, |ui| self.view.ui(ui));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
use crate::egui_preview_setup::{EguiPreviewCase, EguiPreviewSetup};
|
|
||||||
use notedeck::account_login_view::{DesktopAccountLoginView, MobileAccountLoginView};
|
|
||||||
use notedeck::login_manager::LoginManager;
|
|
||||||
|
|
||||||
pub struct DesktopAccountLoginPreview {
|
|
||||||
manager: LoginManager,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl EguiPreviewCase for DesktopAccountLoginPreview {
|
|
||||||
fn new(_supr: EguiPreviewSetup) -> Self {
|
|
||||||
DesktopAccountLoginPreview {
|
|
||||||
manager: LoginManager::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl eframe::App for DesktopAccountLoginPreview {
|
|
||||||
fn update(&mut self, ctx: &egui::Context, _: &mut eframe::Frame) {
|
|
||||||
DesktopAccountLoginView::new(ctx, &mut self.manager).panel()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct MobileAccountLoginPreview {
|
|
||||||
manager: LoginManager,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl EguiPreviewCase for MobileAccountLoginPreview {
|
|
||||||
fn new(_supr: EguiPreviewSetup) -> Self {
|
|
||||||
MobileAccountLoginPreview {
|
|
||||||
manager: LoginManager::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl eframe::App for MobileAccountLoginPreview {
|
|
||||||
fn update(&mut self, ctx: &egui::Context, _: &mut eframe::Frame) {
|
|
||||||
MobileAccountLoginView::new(ctx, &mut self.manager).panel()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
use notedeck::app_creation::setup_cc;
|
|
||||||
|
|
||||||
pub struct EguiPreviewSetup {}
|
|
||||||
|
|
||||||
pub trait EguiPreviewCase: eframe::App {
|
|
||||||
fn new(supr: EguiPreviewSetup) -> Self;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl EguiPreviewSetup {
|
|
||||||
pub fn new(cc: &eframe::CreationContext<'_>) -> Self {
|
|
||||||
setup_cc(cc);
|
|
||||||
|
|
||||||
EguiPreviewSetup {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,57 +1,72 @@
|
|||||||
mod account_login_preview;
|
use notedeck::account_login_view::AccountLoginView;
|
||||||
mod egui_preview_setup;
|
use notedeck::app_creation::{
|
||||||
mod relay_view_preview;
|
generate_mobile_emulator_native_options, generate_native_options, setup_cc,
|
||||||
use account_login_preview::{DesktopAccountLoginPreview, MobileAccountLoginPreview};
|
};
|
||||||
use egui_preview_setup::{EguiPreviewCase, EguiPreviewSetup};
|
use notedeck::relay_view::RelayView;
|
||||||
use notedeck::app_creation::{generate_mobile_emulator_native_options, generate_native_options};
|
use notedeck::ui::{Preview, PreviewApp};
|
||||||
use relay_view_preview::RelayViewPreview;
|
|
||||||
use std::env;
|
use std::env;
|
||||||
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
struct PreviewRunner {
|
||||||
#[tokio::main]
|
force_mobile: bool,
|
||||||
async fn run_test_app<F, T, O>(create_supr: F, create_child: O, is_mobile: bool)
|
|
||||||
where
|
|
||||||
F: 'static + FnOnce(&eframe::CreationContext<'_>) -> EguiPreviewSetup,
|
|
||||||
T: 'static + EguiPreviewCase,
|
|
||||||
O: 'static + FnOnce(EguiPreviewSetup) -> T,
|
|
||||||
{
|
|
||||||
tracing_subscriber::fmt::init();
|
|
||||||
|
|
||||||
let native_options = if is_mobile {
|
|
||||||
generate_mobile_emulator_native_options()
|
|
||||||
} else {
|
|
||||||
generate_native_options()
|
|
||||||
};
|
|
||||||
|
|
||||||
let _ = eframe::run_native(
|
|
||||||
"UI Preview Runner",
|
|
||||||
native_options,
|
|
||||||
Box::new(|cc| Box::new(create_child(create_supr(cc)))),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
impl PreviewRunner {
|
||||||
let args: Vec<String> = env::args().collect();
|
fn new(force_mobile: bool) -> Self {
|
||||||
|
PreviewRunner { force_mobile }
|
||||||
|
}
|
||||||
|
|
||||||
if args.len() > 1 {
|
async fn run<P>(self, preview: P)
|
||||||
match args[1].as_str() {
|
where
|
||||||
"DesktopAccountLoginPreview" => run_test_app(
|
P: Into<PreviewApp> + 'static,
|
||||||
EguiPreviewSetup::new,
|
{
|
||||||
DesktopAccountLoginPreview::new,
|
tracing_subscriber::fmt::init();
|
||||||
false,
|
|
||||||
),
|
let native_options = if self.force_mobile {
|
||||||
"MobileAccountLoginPreview" => {
|
generate_mobile_emulator_native_options()
|
||||||
run_test_app(EguiPreviewSetup::new, MobileAccountLoginPreview::new, true)
|
} else {
|
||||||
}
|
generate_native_options()
|
||||||
"DesktopRelayViewPreview" => {
|
};
|
||||||
run_test_app(EguiPreviewSetup::new, RelayViewPreview::new, false)
|
|
||||||
}
|
let _ = eframe::run_native(
|
||||||
"MobileRelayViewPreview" => {
|
"UI Preview Runner",
|
||||||
run_test_app(EguiPreviewSetup::new, RelayViewPreview::new, true)
|
native_options,
|
||||||
}
|
Box::new(|cc| {
|
||||||
_ => println!("Component not found."),
|
setup_cc(cc);
|
||||||
}
|
Box::new(Into::<PreviewApp>::into(preview))
|
||||||
} else {
|
}),
|
||||||
println!("Please specify a component to test.");
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() {
|
||||||
|
let mut name: Option<String> = None;
|
||||||
|
let mut is_mobile = false;
|
||||||
|
|
||||||
|
for arg in env::args() {
|
||||||
|
if arg == "--mobile" {
|
||||||
|
is_mobile = true;
|
||||||
|
} else {
|
||||||
|
name = Some(arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let name = if let Some(name) = name {
|
||||||
|
name
|
||||||
|
} else {
|
||||||
|
println!("Please specify a component to test");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let runner = PreviewRunner::new(is_mobile);
|
||||||
|
|
||||||
|
match name.as_ref() {
|
||||||
|
"AccountLoginView" => {
|
||||||
|
runner.run(AccountLoginView::preview()).await;
|
||||||
|
}
|
||||||
|
"RelayView" => {
|
||||||
|
runner.run(RelayView::preview()).await;
|
||||||
|
}
|
||||||
|
_ => println!("Component not found."),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,35 +0,0 @@
|
|||||||
use enostr::RelayPool;
|
|
||||||
use notedeck::{relay_pool_manager::RelayPoolManager, relay_view::RelayView};
|
|
||||||
|
|
||||||
use crate::egui_preview_setup::{EguiPreviewCase, EguiPreviewSetup};
|
|
||||||
|
|
||||||
pub struct RelayViewPreview {
|
|
||||||
pool: RelayPool,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(unused_must_use)]
|
|
||||||
impl EguiPreviewCase for RelayViewPreview {
|
|
||||||
fn new(_supr: EguiPreviewSetup) -> Self {
|
|
||||||
let mut pool = RelayPool::new();
|
|
||||||
let wakeup = move || {};
|
|
||||||
|
|
||||||
pool.add_url("wss://relay.damus.io".to_string(), wakeup);
|
|
||||||
pool.add_url("wss://eden.nostr.land".to_string(), wakeup);
|
|
||||||
pool.add_url("wss://nostr.wine".to_string(), wakeup);
|
|
||||||
pool.add_url("wss://nos.lol".to_string(), wakeup);
|
|
||||||
pool.add_url("wss://test_relay_url_long_00000000000000000000000000000000000000000000000000000000000000000000000000000000000".to_string(), wakeup);
|
|
||||||
|
|
||||||
for _ in 0..20 {
|
|
||||||
pool.add_url("tmp".to_string(), wakeup);
|
|
||||||
}
|
|
||||||
|
|
||||||
RelayViewPreview { pool }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl eframe::App for RelayViewPreview {
|
|
||||||
fn update(&mut self, ctx: &egui::Context, _: &mut eframe::Frame) {
|
|
||||||
self.pool.try_recv();
|
|
||||||
RelayView::new(ctx, RelayPoolManager::new(&mut self.pool)).panel();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user