From c9a8c637c47164bfcf0eda02306121de04f569c7 Mon Sep 17 00:00:00 2001 From: Thomas Eppers Date: Fri, 22 Oct 2021 17:23:37 +0200 Subject: [PATCH] rewrote TagList with a new behaviour --- src/tags.rs | 18 +--- src/ui/default.rs | 20 ++--- src/ui/no_yaml.rs | 34 +++++--- src/widget/info.rs | 2 +- src/widget/tag_list.rs | 181 +++++++++++++++++++++-------------------- 5 files changed, 126 insertions(+), 129 deletions(-) diff --git a/src/tags.rs b/src/tags.rs index 30120de..39e9b4c 100644 --- a/src/tags.rs +++ b/src/tags.rs @@ -4,7 +4,7 @@ use crate::repo; use chrono::DateTime; use serde::Deserialize; -#[derive(Deserialize, Debug)] +#[derive(Deserialize, Debug, Clone)] struct ImageDetails { architecture: String, // os: String, @@ -17,7 +17,7 @@ impl fmt::Display for ImageDetails { } } -#[derive(Deserialize)] +#[derive(Deserialize, Clone)] pub struct Images { images: Vec, #[serde(rename(deserialize = "name"))] @@ -29,9 +29,7 @@ pub struct Images { pub struct Tags { count: usize, #[serde(rename(deserialize = "next"))] - next_page: Option, - #[serde(rename(deserialize = "previous"))] - prev_page: Option, + pub next_page: Option, pub results: Vec, } @@ -43,7 +41,6 @@ pub enum Error { Converting(String), /// invalid repos show a valid json with 0 tags NoTagsFound, - NoPrevPage, NoNextPage, } @@ -53,7 +50,6 @@ impl fmt::Display for Error { Error::Fetching(s) => write!(f, "Fetching error: {}", s), Error::Converting(s) => write!(f, "Converting error: {}", s), Error::NoNextPage => write!(f, "No next page available"), - Error::NoPrevPage => write!(f, "No previous page available"), Error::NoTagsFound => write!(f, "Given Repo has 0 tags. Is it valid?"), } } @@ -108,14 +104,6 @@ impl Tags { None => Err(Error::NoNextPage), } } - - /// returns tags of previous page - pub fn prev_page(&self) -> Result { - match &self.prev_page { - Some(url) => Self::with_url(url), - None => Err(Error::NoPrevPage), - } - } } impl fmt::Display for Images { diff --git a/src/ui/default.rs b/src/ui/default.rs index 5d84bba..6636f00 100644 --- a/src/ui/default.rs +++ b/src/ui/default.rs @@ -44,7 +44,7 @@ impl Ui { pub fn run(opt: &Opt) { let (repo_id, load_repo) = match &opt.repo { None => ( - "enter a repository or select one from docker-compose.yml", + "enter a repository here or select one from file widget", false, ), Some(repo) => (String::as_str(repo), true), @@ -59,7 +59,7 @@ impl Ui { }; if load_repo { - ui.tags = tag_list::TagList::with_repo(ui.repo.get()); + ui.tags = tag_list::TagList::with_repo_name(ui.repo.get()); } //setup tui @@ -113,20 +113,12 @@ impl Ui { }, Ok(Key::Ctrl('r')) => { ui.repo.confirm(); - ui.tags = tag_list::TagList::with_repo(ui.repo.get()); + ui.tags = tag_list::TagList::with_repo_name(ui.repo.get()); } - Ok(Key::Ctrl('n')) => match ui.tags.next_page() { - Err(e) => ui.info.set_info(&format!("{}", e)), - Ok(_) => (), - }, - Ok(Key::Ctrl('p')) => match ui.tags.prev_page() { - Err(e) => ui.info.set_info(&format!("{}", e)), - Ok(_) => (), - }, Ok(Key::Char('\n')) => match ui.state { State::EditRepo => { ui.repo.confirm(); - ui.tags = tag_list::TagList::with_repo(ui.repo.get()); + ui.tags = tag_list::TagList::with_repo_name(ui.repo.get()); } State::SelectTag => { let mut repo = ui.repo.get(); @@ -172,7 +164,7 @@ impl Ui { Ok(s) => s, }; ui.repo.set(repo.to_string()); - ui.tags = tag_list::TagList::with_repo(ui.repo.get()); + ui.tags = tag_list::TagList::with_repo_name(ui.repo.get()); } } } @@ -193,7 +185,7 @@ impl Ui { Ok(s) => s, }; ui.repo.set(repo.to_string()); - ui.tags = tag_list::TagList::with_repo(ui.repo.get()); + ui.tags = tag_list::TagList::with_repo_name(ui.repo.get()); } } } diff --git a/src/ui/no_yaml.rs b/src/ui/no_yaml.rs index 86c7e9c..dfb9629 100644 --- a/src/ui/no_yaml.rs +++ b/src/ui/no_yaml.rs @@ -57,7 +57,7 @@ impl NoYaml { // load tags if a repository was given thorugh paramter if load_repo { - ui.tags = tag_list::TagList::with_repo(ui.repo.get()); + ui.tags = tag_list::TagList::with_repo_name(ui.repo.get()); } //setup tui @@ -100,22 +100,17 @@ impl NoYaml { } Ok(Key::Ctrl('r')) => { ui.repo.confirm(); - ui.tags = tag_list::TagList::with_repo(ui.repo.get()); + ui.tags = tag_list::TagList::with_repo_name(ui.repo.get()); } - Ok(Key::Ctrl('n')) => match ui.tags.next_page() { - Err(e) => ui.info.set_info(&format!("{}", e)), - Ok(_) => (), - }, - Ok(Key::Ctrl('p')) => match ui.tags.prev_page() { - Err(e) => ui.info.set_info(&format!("{}", e)), - Ok(_) => (), - }, Ok(Key::Char('\n')) => match ui.state { State::EditRepo => { ui.repo.confirm(); - ui.tags = tag_list::TagList::with_repo(ui.repo.get()); + ui.tags = tag_list::TagList::with_repo_name(ui.repo.get()); + } + State::SelectTag => { + ui.tags.get_selected(); + () } - _ => (), }, Ok(Key::Char(key)) => match ui.state { State::EditRepo => { @@ -126,6 +121,21 @@ impl NoYaml { ui.tags.handle_input(Key::Char(key)); } }, + Ok(Key::Backspace) => match ui.state { + State::EditRepo => { + ui.info.set_info("Editing Repository"); + ui.repo.handle_input(Key::Backspace); + } + State::SelectTag => (), + }, + Ok(Key::Up) => match ui.state { + State::EditRepo => (), + State::SelectTag => ui.tags.handle_input(Key::Up), + }, + Ok(Key::Down) => match ui.state { + State::EditRepo => (), + State::SelectTag => ui.tags.handle_input(Key::Down), + }, _ => (), } diff --git a/src/widget/info.rs b/src/widget/info.rs index a2b5772..39caae8 100644 --- a/src/widget/info.rs +++ b/src/widget/info.rs @@ -11,7 +11,7 @@ impl Info { Self { info: String::from(info), keys: String::from( - "Tab Cycle widgets C-s Save C-r Reload C-q Quit C-n Next page C-p Previous page ↑ ↓ Select tags or image line", + "Tab Cycle widgets C-s Save C-r Reload C-q Quit ↑ ↓ Select tags or image line", ), } } diff --git a/src/widget/tag_list.rs b/src/widget/tag_list.rs index 681427d..34eed1c 100644 --- a/src/widget/tag_list.rs +++ b/src/widget/tag_list.rs @@ -6,105 +6,77 @@ use tui::widgets::{Block, Borders, List, ListState}; use crate::tags; -#[derive(Debug)] pub enum Error { NoneSelected, - NoTags, - NoNextPage, - NoPrevPage, + NextPageSelected, + SelectedStatus, } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - Error::NoTags => write!(f, "There are no tags"), Error::NoneSelected => write!(f, "No tag selected"), - Error::NoNextPage => write!(f, "No next page available"), - Error::NoPrevPage => write!(f, "No previous page available"), + Error::NextPageSelected => write!(f, "tried to get the next page"), + Error::SelectedStatus => write!(f, "Status message was selected"), } } } -/// used for creating a TagList -pub enum Type { +enum Line { Status(String), - Repo(tags::Tags), + Image(tags::Images), +} + +impl fmt::Display for Line { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Line::Status(s) => write!(f, "{}", s), + Line::Image(i) => write!(f, "{}", i), + } + } } pub struct TagList { - typ: Type, + lines: Vec, state: ListState, + tags: Option, } impl TagList { - fn new(typ: Type) -> Self { - Self { - typ, - state: ListState::default(), - } - } - - /// create a TagList with a status message pub fn with_status(status: &str) -> Self { - Self::new(Type::Status(String::from(status))) - } - - /// create a TagList - pub fn with_repo(name: String) -> Self { - match tags::Tags::new(name) { - Err(e) => Self::with_status(&format!("{}", e)), - Ok(tags) => Self::new(Type::Repo(tags)), + Self { + lines: vec![Line::Status(String::from(status))], + state: ListState::default(), + tags: None, } } - /// display next page if possible - pub fn next_page(&mut self) -> Result<(), Error> { - match &self.typ { - Type::Status(_) => (), - Type::Repo(tags) => match tags.next_page() { - Err(_) => return Err(Error::NoNextPage), - Ok(tags) => self.typ = Type::Repo(tags), - }, - } - Ok(()) - } - - /// display previous page if possible - pub fn prev_page(&mut self) -> Result<(), Error> { - match &self.typ { - Type::Status(_) => (), - Type::Repo(tags) => match tags.prev_page() { - Err(_) => return Err(Error::NoPrevPage), - Ok(tags) => self.typ = Type::Repo(tags), - }, - } - Ok(()) - } - - /// get a list of tag names with info - fn print_lines(&self) -> Vec { - match &self.typ { - Type::Status(line) => vec![line.to_string()], - Type::Repo(tags) => tags.results.iter().map(|r| format!("{}", r)).collect(), + pub fn with_repo_name(repo: String) -> Self { + match tags::Tags::new(repo) { + Ok(tags) => Self::with_tags(tags), + Err(_) => Self::with_status("input repo was not found"), } } - /// get the list of tag names - pub fn get_names(&self) -> Result, Error> { - match &self.typ { - Type::Status(_) => Err(Error::NoTags), - Type::Repo(tags) => Ok(tags.results.iter().map(|r| r.tag_name.clone()).collect()), - } - } + pub fn with_tags(mut tags: tags::Tags) -> Self { + let mut lines: Vec = tags + .results + .iter() + .map(|r| Line::Image(r.clone())) + .collect(); - /// get the selected tag or return an error - pub fn get_selected(&self) -> Result { - match &self.typ { - Type::Status(_) => Err(Error::NoTags), - Type::Repo(_) => match self.state.selected() { - None => Err(Error::NoneSelected), - Some(i) => Ok(self.get_names().unwrap()[i].clone()), - }, + match tags.next_page() { + Err(_) => (), + Ok(new_tags) => { + lines.push(Line::Status(String::from("load more tags"))); + tags = new_tags; + } + }; + + Self { + lines, + state: ListState::default(), + tags: Some(tags), } } @@ -115,15 +87,11 @@ impl TagList { Style::default().fg(Color::Gray) }; - let lines = match &self.typ { - Type::Status(line) => vec![line.clone()], - Type::Repo(_) => self.print_lines(), - }; - - let items: Vec = lines + let items: Vec = self + .lines .iter() .map(|l| { - tui::widgets::ListItem::new(l.clone()) + tui::widgets::ListItem::new(format!("{}", l)) .style(Style::default().fg(Color::White).bg(Color::Black)) }) .collect(); @@ -151,24 +119,63 @@ impl TagList { } } - /// select next tag - pub fn next(&mut self) { + pub fn get_selected(&mut self) -> Result { match self.state.selected() { - None if self.print_lines().len() > 0 => self.state.select(Some(0)), + None => Err(Error::NoneSelected), + Some(i) if i == self.lines.len() - 1 => { + self.load_next_page(); + Err(Error::NextPageSelected) + } + Some(i) => match &self.lines[i] { + Line::Status(_) => Err(Error::SelectedStatus), + Line::Image(i) => Ok(i.tag_name.clone()), + }, + } + } + + fn load_next_page(&mut self) { + match &self.tags { + Some(tags) => match tags.next_page() { + Err(_) => (), + Ok(new_tags) => { + //load new tags object + self.tags = Some(new_tags); + + //remove "load next page" + let next_page = self.lines.pop(); + + //add tags + for image in &self.tags.as_ref().unwrap().results { + self.lines.push(Line::Image(image.clone())); + } + + //readd next page + match self.tags.as_ref().unwrap().next_page { + None => (), + Some(_) => self.lines.push(next_page.unwrap()), + } + } + }, None => (), - Some(i) if i == self.print_lines().len() - 1 => self.state.select(Some(0)), + } + } + + /// select next tag + fn next(&mut self) { + match self.state.selected() { + None if self.lines.len() > 0 => self.state.select(Some(0)), + None => (), + Some(i) if i == self.lines.len() - 1 => self.state.select(Some(0)), Some(i) => self.state.select(Some(i + 1)), } } /// select previous tag - pub fn previous(&mut self) { + fn previous(&mut self) { match self.state.selected() { - None if self.print_lines().len() > 0 => { - self.state.select(Some(self.print_lines().len())) - } + None if self.lines.len() > 0 => self.state.select(Some(self.lines.len())), None => (), - Some(i) if i == 0 => self.state.select(Some(self.print_lines().len() - 1)), + Some(i) if i == 0 => self.state.select(Some(self.lines.len() - 1)), Some(i) => self.state.select(Some(i - 1)), } }