use std::sync::OnceLock;
use swiftui_native::prelude::*;
use swiftui_native::{state, views};
struct Message {
from: &'static str,
subject: &'static str,
unread: bool,
}
const MESSAGES: &[Message] = &[
Message { from: "Ada Lovelace", subject: "Notes on the Analytical Engine", unread: true },
Message { from: "Alan Turing", subject: "On computable numbers", unread: true },
Message { from: "Grace Hopper", subject: "Compiler progress", unread: false },
Message { from: "Barbara Liskov", subject: "Substitution", unread: false },
];
struct Inbox {
query: views::BoundState<String>,
searching: views::BoundState<bool>,
}
fn inbox() -> &'static Inbox {
static I: OnceLock<Inbox> = OnceLock::new();
I.get_or_init(|| Inbox {
query: views::BoundState::new(String::new()),
searching: views::BoundState::new(false),
})
}
fn matching() -> Vec<usize> {
let q = inbox().query.get().to_lowercase();
MESSAGES
.iter()
.enumerate()
.filter(|(_, m)| {
q.is_empty()
|| m.from.to_lowercase().contains(&q)
|| m.subject.to_lowercase().contains(&q)
})
.map(|(i, _)| i)
.collect()
}
fn detail(i: usize) -> View {
let m = &MESSAGES[i];
vstack_aligned_spacing(
&[
text(m.subject).text_style(TextStyle::Title).bold(),
text!("From {}", m.from).fg_system(SystemColor::Gray),
divider(),
text("Body text would go here.").fg_system(SystemColor::Gray),
spacer(),
],
HorizontalAlignment::Leading,
Some(12.0),
)
.padding(20.0)
.navigation_title(m.subject)
}
fn row(i: usize) -> View {
let m = &MESSAGES[i];
hstack_spacing(
&[
view_if!(
m.unread,
circle_shape().fill_system(SystemColor::Blue).frame(8.0, 8.0),
empty().frame(8.0, 8.0)
),
vstack_aligned(
&[
text(m.from).bold(),
text(m.subject).font_size(12.0).fg_system(SystemColor::Gray),
],
HorizontalAlignment::Leading,
),
spacer(),
],
8.0,
)
.padding_edges(EdgeSet::Vertical, Some(4.0))
.a11y_label(&format!("{}, {}", m.from, m.subject))
.a11y_hint(if m.unread { "Unread" } else { "Read" })
}
fn linked_row(i: usize) -> View {
navigation_link_labelled(row(i), detail(i))
.swipe_actions(HorizontalEdge::Trailing, true, button("Delete", || {}))
}
fn body() -> View {
let i = inbox();
let rows = matching();
navigation_stack(
list(for_each_items(&rows, |&i| linked_row(i)))
.list_style(views::ListStyle::InsetListStyle)
.searchable(&i.query, &i.searching, SearchFieldPlacement::Automatic, "Search"),
)
.navigation_title("Inbox")
.toolbar(button("Compose", || {}).keyboard_shortcut(KeyboardShortcut::DefaultAction))
}
fn content_view() -> swiftui_native::ViewHandle {
state::root_view(|_| body().into_handle())
}
#[cfg(target_os = "macos")]
#[path = "common/simulator.rs"]
mod simulator;
#[cfg(target_os = "macos")]
fn main() {
if std::env::args().any(|a| a == "--sim" || a == "device") {
return simulator::main(&simulator::Bundle {
example: "inbox",
bundle_id: "dev.rswift.Inbox",
executable: "Inbox",
display_name: "Inbox",
launch_args: &[],
});
}
if std::env::args().any(|a| a == "--render") {
let out = concat!(env!("CARGO_MANIFEST_DIR"), "/../../target/inbox.png");
swiftui_native::render::render(&content_view(), 420, 520).write_png(out);
eprintln!("wrote {out}");
return;
}
show_window(&content_view(), "Inbox", 420.0, 520.0);
}
#[cfg(not(target_os = "macos"))]
fn main() {
swiftui_native::app::run(content_view)
}