first commit
This commit is contained in:
180
src/app.rs
Normal file
180
src/app.rs
Normal file
@@ -0,0 +1,180 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
// ─── Domain types ─────────────────────────────────────────────────────────────
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct Space {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct Page {
|
||||
pub id: String,
|
||||
pub title: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct DataWrapper<T> {
|
||||
pub items: Vec<T>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum ApiList<T> {
|
||||
Wrapped { data: DataWrapper<T> },
|
||||
Paginated { items: Vec<T> },
|
||||
Plain(Vec<T>),
|
||||
}
|
||||
|
||||
impl<T> ApiList<T> {
|
||||
pub fn into_items(self) -> Vec<T> {
|
||||
match self {
|
||||
ApiList::Wrapped { data } => data.items,
|
||||
ApiList::Paginated { items } => items,
|
||||
ApiList::Plain(v) => v,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ─── Login form ───────────────────────────────────────────────────────────────
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum AppState {
|
||||
Login,
|
||||
Main,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum LoginField {
|
||||
Url,
|
||||
Email,
|
||||
Password,
|
||||
}
|
||||
|
||||
impl LoginField {
|
||||
pub fn next(self) -> Self {
|
||||
match self {
|
||||
LoginField::Url => LoginField::Email,
|
||||
LoginField::Email => LoginField::Password,
|
||||
LoginField::Password => LoginField::Url,
|
||||
}
|
||||
}
|
||||
pub fn prev(self) -> Self {
|
||||
match self {
|
||||
LoginField::Url => LoginField::Password,
|
||||
LoginField::Email => LoginField::Url,
|
||||
LoginField::Password => LoginField::Email,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct LoginForm {
|
||||
pub url: String,
|
||||
pub email: String,
|
||||
pub password: String,
|
||||
pub active_field: LoginField,
|
||||
pub error: Option<String>,
|
||||
pub submitting: bool,
|
||||
}
|
||||
|
||||
impl LoginForm {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
url: String::from("https://docmost.nakano47.com"),
|
||||
email: String::from("chamagua1@proton.me"),
|
||||
password: String::new(),
|
||||
active_field: LoginField::Email,
|
||||
error: None,
|
||||
submitting: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn active_field_value_mut(&mut self) -> &mut String {
|
||||
match self.active_field {
|
||||
LoginField::Url => &mut self.url,
|
||||
LoginField::Email => &mut self.email,
|
||||
LoginField::Password => &mut self.password,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ─── Main view ────────────────────────────────────────────────────────────────
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum Panel {
|
||||
Spaces,
|
||||
Pages,
|
||||
}
|
||||
|
||||
pub struct MainView {
|
||||
pub spaces: Vec<Space>,
|
||||
pub pages: Vec<Page>,
|
||||
pub selected_space: usize,
|
||||
pub selected_page: usize,
|
||||
pub focus: Panel,
|
||||
pub loading_spaces: bool,
|
||||
pub loading_pages: bool,
|
||||
pub error: Option<String>,
|
||||
}
|
||||
|
||||
impl MainView {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
spaces: vec![],
|
||||
pages: vec![],
|
||||
selected_space: 0,
|
||||
selected_page: 0,
|
||||
focus: Panel::Spaces,
|
||||
loading_spaces: true,
|
||||
loading_pages: false,
|
||||
error: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ─── Root app ─────────────────────────────────────────────────────────────────
|
||||
|
||||
pub struct App {
|
||||
pub state: AppState,
|
||||
pub login: LoginForm,
|
||||
pub main: MainView,
|
||||
pub base_url: String,
|
||||
pub token: String,
|
||||
}
|
||||
|
||||
impl App {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
state: AppState::Login,
|
||||
login: LoginForm::new(),
|
||||
main: MainView::new(),
|
||||
base_url: String::new(),
|
||||
token: String::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ─── Messages ─────────────────────────────────────────────────────────────────
|
||||
|
||||
pub enum AppMsg {
|
||||
LoginSuccess { token: String, base_url: String },
|
||||
LoginError(String),
|
||||
SpacesLoaded(Vec<Space>),
|
||||
PagesLoaded(Vec<Page>),
|
||||
ApiError(String),
|
||||
}
|
||||
|
||||
// ─── Request DTOs ─────────────────────────────────────────────────────────────
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct LoginRequest<'a> {
|
||||
pub email: &'a str,
|
||||
pub password: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct SidebarPagesRequest<'a> {
|
||||
#[serde(rename = "spaceId")]
|
||||
pub space_id: &'a str,
|
||||
}
|
||||
Reference in New Issue
Block a user