asaru 0.3.4

Asana Tasks Search CLI
use std::collections::HashSet;

use anyhow::Result;
use futures::future;

use crate::asana;

pub(crate) struct State {
    workspace_gid: String,
    pats: String,
    text: String,
    tasks: Vec<asana::SearchTasksData>,
    index: usize,
    checked: HashSet<usize>,
}

impl State {
    pub fn text(&self) -> &str {
        &self.text
    }

    pub fn tasks(&self) -> &[asana::SearchTasksData] {
        &self.tasks
    }

    pub fn index(&self) -> usize {
        self.index
    }

    pub fn checked(&self) -> &HashSet<usize> {
        &self.checked
    }

    pub fn new(workspace_gid: &str, pats: &str) -> Self {
        State {
            text: String::new(),
            tasks: Vec::new(),
            workspace_gid: workspace_gid.to_string(),
            pats: pats.to_string(),
            index: 0,
            checked: HashSet::new(),
        }
    }

    pub fn clear_checked(mut self) -> Self {
        self.checked = HashSet::new();
        self
    }

    pub fn clear_index(mut self) -> Self {
        self.index = 0;
        self
    }

    pub fn dec_index(mut self) -> Self {
        self.index -= 1;
        self
    }

    pub fn inc_index(mut self) -> Self {
        self.index += 1;
        self
    }

    pub fn edit_index(mut self, index: usize) -> Self {
        self.index = index;
        self
    }

    pub fn edit_text(mut self, text: &str) -> Self {
        self.text = text.to_string();
        self
    }

    pub async fn search(mut self) -> Result<Self> {
        let tasks = asana::search_tasks(&self.workspace_gid, &self.text, &self.pats)
            .await?
            .data;
        self.tasks = tasks;
        Ok(self)
    }

    pub async fn get_permalink_url(&self) -> Option<String> {
        match self.tasks.get(self.index) {
            Some(t) => t.get_permalink_url(&self.pats).await.ok(),
            None => None,
        }
    }

    pub fn get_titles(&self) -> Vec<String> {
        self.tasks
            .iter()
            .map(|t| t.name.clone())
            .collect::<Vec<_>>()
    }

    pub fn is_checked(&self, index: &usize) -> bool {
        self.checked.contains(index)
    }

    pub fn check(mut self) -> Self {
        if self.tasks.len() > self.index {
            let mut hs = self.checked;
            hs.insert(self.index);
            self.checked = hs;
            return self;
        }

        self
    }

    pub fn uncheck(mut self) -> Self {
        let mut hs = self.checked;
        hs.remove(&self.index);
        self.checked = hs;
        self
    }

    pub async fn get_checked_permalink_urls(&self) -> Vec<String> {
        let res = future::join_all({
            self.checked
                .iter()
                .flat_map(|&i| self.tasks.get(i))
                .map(|t| async move { t.get_permalink_url(&self.pats).await })
        })
        .await;

        res.iter()
            .flat_map(|r| r.as_ref().ok())
            .map(|s| s.to_string())
            .collect::<Vec<_>>()
    }
}