207 lines
5.3 KiB
Rust
207 lines
5.3 KiB
Rust
pub mod event;
|
|
pub mod page;
|
|
pub mod subscription;
|
|
|
|
use anyhow::Result;
|
|
|
|
use radicle::cob::issue::IssueId;
|
|
use radicle::cob::patch::PatchId;
|
|
use radicle::identity::{Id, Project};
|
|
use radicle::profile::Profile;
|
|
|
|
use tuirealm::application::PollStrategy;
|
|
use tuirealm::{Application, Frame, NoUserEvent};
|
|
|
|
use radicle_tui::ui::context::Context;
|
|
use radicle_tui::ui::theme::{self, Theme};
|
|
use radicle_tui::Tui;
|
|
use radicle_tui::{cob, ui};
|
|
|
|
use page::{HomeView, PatchView};
|
|
|
|
use self::page::{IssuePage, PageStack};
|
|
|
|
#[derive(Debug, Eq, PartialEq, Clone, Hash)]
|
|
pub enum HomeCid {
|
|
Header,
|
|
Dashboard,
|
|
IssueBrowser,
|
|
PatchBrowser,
|
|
}
|
|
|
|
#[derive(Debug, Eq, PartialEq, Clone, Hash)]
|
|
pub enum PatchCid {
|
|
Header,
|
|
Activity,
|
|
Files,
|
|
}
|
|
|
|
#[derive(Debug, Eq, PartialEq, Clone, Hash)]
|
|
pub enum IssueCid {
|
|
List,
|
|
Details,
|
|
Shortcuts,
|
|
}
|
|
|
|
/// All component ids known to this application.
|
|
#[derive(Debug, Eq, PartialEq, Clone, Hash)]
|
|
pub enum Cid {
|
|
Home(HomeCid),
|
|
Issue(IssueCid),
|
|
Patch(PatchCid),
|
|
GlobalListener,
|
|
}
|
|
|
|
/// Messages handled by this application.
|
|
#[derive(Debug, Eq, PartialEq)]
|
|
pub enum HomeMessage {}
|
|
|
|
#[derive(Debug, Eq, PartialEq)]
|
|
pub enum IssueMessage {
|
|
Show(IssueId),
|
|
Changed(IssueId),
|
|
Leave,
|
|
}
|
|
|
|
#[derive(Debug, Eq, PartialEq)]
|
|
pub enum PatchMessage {
|
|
Show(PatchId),
|
|
Leave,
|
|
}
|
|
|
|
#[derive(Debug, Eq, PartialEq)]
|
|
pub enum Message {
|
|
Home(HomeMessage),
|
|
Issue(IssueMessage),
|
|
Patch(PatchMessage),
|
|
NavigationChanged(u16),
|
|
Tick,
|
|
Quit,
|
|
}
|
|
|
|
#[allow(dead_code)]
|
|
pub struct App {
|
|
context: Context,
|
|
pages: PageStack,
|
|
theme: Theme,
|
|
quit: bool,
|
|
}
|
|
|
|
/// Creates a new application using a tui-realm-application, mounts all
|
|
/// components and sets focus to a default one.
|
|
impl App {
|
|
pub fn new(profile: Profile, id: Id, project: Project) -> Self {
|
|
Self {
|
|
context: Context::new(profile, id, project),
|
|
pages: PageStack::default(),
|
|
theme: theme::default_dark(),
|
|
quit: false,
|
|
}
|
|
}
|
|
|
|
fn view_home(
|
|
&mut self,
|
|
app: &mut Application<Cid, Message, NoUserEvent>,
|
|
theme: &Theme,
|
|
) -> Result<()> {
|
|
let home = Box::<HomeView>::default();
|
|
self.pages.push(home, app, &self.context, theme)?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn view_patch(
|
|
&mut self,
|
|
app: &mut Application<Cid, Message, NoUserEvent>,
|
|
id: PatchId,
|
|
theme: &Theme,
|
|
) -> Result<()> {
|
|
let repo = self.context.repository();
|
|
|
|
if let Some(patch) = cob::patch::find(repo, &id)? {
|
|
let view = Box::new(PatchView::new((id, patch)));
|
|
self.pages.push(view, app, &self.context, theme)?;
|
|
|
|
Ok(())
|
|
} else {
|
|
Err(anyhow::anyhow!(
|
|
"Could not mount 'page::PatchView'. Patch not found."
|
|
))
|
|
}
|
|
}
|
|
|
|
fn view_issue(
|
|
&mut self,
|
|
app: &mut Application<Cid, Message, NoUserEvent>,
|
|
id: IssueId,
|
|
theme: &Theme,
|
|
) -> Result<()> {
|
|
let repo = self.context.repository();
|
|
|
|
if let Some(issue) = cob::issue::find(repo, &id)? {
|
|
let view = Box::new(IssuePage::new((id, issue)));
|
|
self.pages.push(view, app, &self.context, theme)?;
|
|
|
|
Ok(())
|
|
} else {
|
|
Err(anyhow::anyhow!(
|
|
"Could not mount 'page::IssueView'. Issue not found."
|
|
))
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Tui<Cid, Message> for App {
|
|
fn init(&mut self, app: &mut Application<Cid, Message, NoUserEvent>) -> Result<()> {
|
|
self.view_home(app, &self.theme.clone())?;
|
|
|
|
// Add global key listener and subscribe to key events
|
|
let global = ui::widget::common::global_listener().to_boxed();
|
|
app.mount(Cid::GlobalListener, global, subscription::global())?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn view(&mut self, app: &mut Application<Cid, Message, NoUserEvent>, frame: &mut Frame) {
|
|
if let Ok(page) = self.pages.peek_mut() {
|
|
page.view(app, frame);
|
|
}
|
|
}
|
|
|
|
fn update(&mut self, app: &mut Application<Cid, Message, NoUserEvent>) -> Result<bool> {
|
|
match app.tick(PollStrategy::Once) {
|
|
Ok(messages) if !messages.is_empty() => {
|
|
let theme = theme::default_dark();
|
|
for message in messages {
|
|
match message {
|
|
Message::Issue(IssueMessage::Show(id)) => {
|
|
self.view_issue(app, id, &theme)?;
|
|
}
|
|
Message::Issue(IssueMessage::Leave) => {
|
|
self.pages.pop(app)?;
|
|
}
|
|
Message::Patch(PatchMessage::Show(id)) => {
|
|
self.view_patch(app, id, &theme)?;
|
|
}
|
|
Message::Patch(PatchMessage::Leave) => {
|
|
self.pages.pop(app)?;
|
|
}
|
|
Message::Quit => self.quit = true,
|
|
_ => {
|
|
self.pages
|
|
.peek_mut()?
|
|
.update(app, &self.context, &theme, message)?;
|
|
}
|
|
}
|
|
}
|
|
Ok(true)
|
|
}
|
|
_ => Ok(false),
|
|
}
|
|
}
|
|
|
|
fn quit(&self) -> bool {
|
|
self.quit
|
|
}
|
|
}
|