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:
William Casarin
2024-04-19 14:09:19 -07:00
parent a5e1fbf328
commit a71e8206fb
11 changed files with 313 additions and 284 deletions

View File

@@ -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()
}
}

View File

@@ -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 {}
}
}

View File

@@ -1,57 +1,72 @@
mod account_login_preview;
mod egui_preview_setup;
mod relay_view_preview;
use account_login_preview::{DesktopAccountLoginPreview, MobileAccountLoginPreview};
use egui_preview_setup::{EguiPreviewCase, EguiPreviewSetup};
use notedeck::app_creation::{generate_mobile_emulator_native_options, generate_native_options};
use relay_view_preview::RelayViewPreview;
use notedeck::account_login_view::AccountLoginView;
use notedeck::app_creation::{
generate_mobile_emulator_native_options, generate_native_options, setup_cc,
};
use notedeck::relay_view::RelayView;
use notedeck::ui::{Preview, PreviewApp};
use std::env;
#[cfg(not(target_arch = "wasm32"))]
#[tokio::main]
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)))),
);
struct PreviewRunner {
force_mobile: bool,
}
fn main() {
let args: Vec<String> = env::args().collect();
impl PreviewRunner {
fn new(force_mobile: bool) -> Self {
PreviewRunner { force_mobile }
}
if args.len() > 1 {
match args[1].as_str() {
"DesktopAccountLoginPreview" => run_test_app(
EguiPreviewSetup::new,
DesktopAccountLoginPreview::new,
false,
),
"MobileAccountLoginPreview" => {
run_test_app(EguiPreviewSetup::new, MobileAccountLoginPreview::new, true)
}
"DesktopRelayViewPreview" => {
run_test_app(EguiPreviewSetup::new, RelayViewPreview::new, false)
}
"MobileRelayViewPreview" => {
run_test_app(EguiPreviewSetup::new, RelayViewPreview::new, true)
}
_ => println!("Component not found."),
}
} else {
println!("Please specify a component to test.");
async fn run<P>(self, preview: P)
where
P: Into<PreviewApp> + 'static,
{
tracing_subscriber::fmt::init();
let native_options = if self.force_mobile {
generate_mobile_emulator_native_options()
} else {
generate_native_options()
};
let _ = eframe::run_native(
"UI Preview Runner",
native_options,
Box::new(|cc| {
setup_cc(cc);
Box::new(Into::<PreviewApp>::into(preview))
}),
);
}
}
#[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."),
}
}

View File

@@ -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();
}
}