WIP: Refactor data types
This commit is contained in:
		
							parent
							
								
									9b4341ccf1
								
							
						
					
					
						commit
						c999764a28
					
				
							
								
								
									
										168
									
								
								src/app.rs
									
									
									
									
									
								
							
							
						
						
									
										168
									
								
								src/app.rs
									
									
									
									
									
								
							@ -1,20 +1,26 @@
 | 
				
			|||||||
use indexmap::IndexMap;
 | 
					// use indexmap::IndexMap;
 | 
				
			||||||
use int_enum::IntEnum;
 | 
					// use int_enum::IntEnum;
 | 
				
			||||||
use serde::{Deserialize, Serialize};
 | 
					use serde::{Deserialize, Serialize};
 | 
				
			||||||
use std::cmp::min;
 | 
					use std::cmp::min;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[cfg(test)]
 | 
					#[cfg(test)]
 | 
				
			||||||
mod tests;
 | 
					mod tests;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[repr(usize)]
 | 
					#[derive(Debug, Serialize, Deserialize)]
 | 
				
			||||||
#[derive(
 | 
					pub struct Column {
 | 
				
			||||||
    Deserialize, Serialize, Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, IntEnum,
 | 
					    pub name: String,
 | 
				
			||||||
)]
 | 
					    pub selected_task_idx: usize,
 | 
				
			||||||
pub enum TaskStatus {
 | 
					    pub tasks: Vec<Task>,
 | 
				
			||||||
    Todo = 0,
 | 
					}
 | 
				
			||||||
    InProgress = 1,
 | 
					
 | 
				
			||||||
    Done = 2,
 | 
					impl Column {
 | 
				
			||||||
    Ideas = 3,
 | 
					    pub fn get_selected_task(&self) -> Option<&Task> {
 | 
				
			||||||
 | 
					        self.tasks.get(self.selected_task_idx)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn get_selected_task_mut(&mut self) -> Option<&mut Task> {
 | 
				
			||||||
 | 
					        self.tasks.get_mut(self.selected_task_idx)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// #[derive(Deserialize, Serialize, Debug, Clone, Copy)]
 | 
					// #[derive(Deserialize, Serialize, Debug, Clone, Copy)]
 | 
				
			||||||
@ -37,7 +43,8 @@ impl Default for Task {
 | 
				
			|||||||
#[derive(Deserialize, Serialize, Debug)]
 | 
					#[derive(Deserialize, Serialize, Debug)]
 | 
				
			||||||
pub struct Project {
 | 
					pub struct Project {
 | 
				
			||||||
    pub name: String,
 | 
					    pub name: String,
 | 
				
			||||||
    pub tasks_per_column: IndexMap<TaskStatus, Vec<Task>>,
 | 
					    pub selected_column_idx: usize,
 | 
				
			||||||
 | 
					    pub columns: Vec<Column>
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug, thiserror::Error)]
 | 
					#[derive(Debug, thiserror::Error)]
 | 
				
			||||||
@ -52,12 +59,8 @@ impl Project {
 | 
				
			|||||||
    pub fn new(name: &str) -> Self {
 | 
					    pub fn new(name: &str) -> Self {
 | 
				
			||||||
        Project {
 | 
					        Project {
 | 
				
			||||||
            name: name.to_owned(),
 | 
					            name: name.to_owned(),
 | 
				
			||||||
            tasks_per_column: IndexMap::from([
 | 
					            columns: vec![],
 | 
				
			||||||
                (TaskStatus::Done, vec![]),
 | 
					            selected_column_idx: 0,
 | 
				
			||||||
                (TaskStatus::Todo, vec![]),
 | 
					 | 
				
			||||||
                (TaskStatus::InProgress, vec![]),
 | 
					 | 
				
			||||||
                (TaskStatus::Ideas, vec![]),
 | 
					 | 
				
			||||||
            ]),
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -70,137 +73,112 @@ impl Project {
 | 
				
			|||||||
        Self::load_from_json(&json)
 | 
					        Self::load_from_json(&json)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn add_task(&mut self, status: TaskStatus, task: Task) {
 | 
					    // pub fn add_task(&mut self, status: Column, task: Task) {
 | 
				
			||||||
        self.tasks_per_column.entry(status).or_default().push(task);
 | 
					    //     self.tasks_per_column.entry(status).or_default().push(task);
 | 
				
			||||||
    }
 | 
					    // }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn save(&self) {
 | 
					    pub fn save(&self) {
 | 
				
			||||||
        let json = serde_json::to_string_pretty(&self).unwrap();
 | 
					        let _json = serde_json::to_string_pretty(&self).unwrap();
 | 
				
			||||||
        std::fs::write("kanban-tui.json", json).unwrap();
 | 
					        // std::fs::write("kanban-tui.json", json).unwrap();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn get_selected_column(&self) -> &Column {
 | 
				
			||||||
 | 
					        &self.columns[self.selected_column_idx]
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn get_selected_column_mut(&mut self) -> &mut Column {
 | 
				
			||||||
 | 
					        &mut self.columns[self.selected_column_idx]
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Default for Project {
 | 
					impl Default for Project {
 | 
				
			||||||
    fn default() -> Self {
 | 
					    fn default() -> Self {
 | 
				
			||||||
        Project {
 | 
					        Project {
 | 
				
			||||||
            name: String::new(),
 | 
					            name: String::new(),
 | 
				
			||||||
            tasks_per_column: IndexMap::new(),
 | 
					            columns: vec![],
 | 
				
			||||||
 | 
					            selected_column_idx: 0,
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub struct AppState {
 | 
					pub struct AppState {
 | 
				
			||||||
    pub selected_column: usize,
 | 
					 | 
				
			||||||
    pub selected_task: [usize; 4],
 | 
					 | 
				
			||||||
    pub project: Project,
 | 
					    pub project: Project,
 | 
				
			||||||
    pub quit: bool,
 | 
					    pub quit: bool,
 | 
				
			||||||
 | 
					    pub columns: Vec<Column>,
 | 
				
			||||||
    pub popup_text: Option<String>,
 | 
					    pub popup_text: Option<String>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl AppState {
 | 
					impl AppState {
 | 
				
			||||||
    pub fn new(project: Project) -> Self {
 | 
					    pub fn new(project: Project) -> Self {
 | 
				
			||||||
        AppState {
 | 
					        AppState {
 | 
				
			||||||
            selected_column: 0,
 | 
					 | 
				
			||||||
            selected_task: [0, 0, 0, 0],
 | 
					 | 
				
			||||||
            quit: false,
 | 
					            quit: false,
 | 
				
			||||||
            popup_text: None,
 | 
					            popup_text: None,
 | 
				
			||||||
            project,
 | 
					            project,
 | 
				
			||||||
 | 
					            columns: vec![],
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn selected_task_idx(&self) -> usize {
 | 
					 | 
				
			||||||
        self.selected_task[self.selected_column]
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn selected_task_idx_mut(&mut self) -> &mut usize {
 | 
					 | 
				
			||||||
        &mut self.selected_task[self.selected_column]
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn get_tasks_in_active_column(&self) -> &[Task] {
 | 
					 | 
				
			||||||
        let column: TaskStatus = TaskStatus::from_int(self.selected_column).unwrap().clone();
 | 
					 | 
				
			||||||
        self.project.tasks_per_column.get(&column).unwrap()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn get_tasks_in_active_column_mut(&mut self) -> &mut Vec<Task> {
 | 
					 | 
				
			||||||
        let column: TaskStatus = TaskStatus::from_int(self.selected_column).unwrap().clone();
 | 
					 | 
				
			||||||
        self.project.tasks_per_column.get_mut(&column).unwrap()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn get_selected_task(&self) -> Option<&Task> {
 | 
					 | 
				
			||||||
        let tasks = self.get_tasks_in_active_column();
 | 
					 | 
				
			||||||
        tasks.get(self.selected_task_idx())
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn select_previous_task(&mut self) {
 | 
					    pub fn select_previous_task(&mut self) {
 | 
				
			||||||
        *self.selected_task_idx_mut() = self.selected_task_idx().saturating_sub(1)
 | 
					        let task_idx = &mut self.project.get_selected_column_mut().selected_task_idx;
 | 
				
			||||||
 | 
					        *task_idx = task_idx.saturating_sub(1)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn select_next_task(&mut self) {
 | 
					    pub fn select_next_task(&mut self) {
 | 
				
			||||||
        let tasks = self.get_tasks_in_active_column();
 | 
					        let column = &mut self.project.get_selected_column_mut();
 | 
				
			||||||
        if tasks.len() > 0 {
 | 
					        let task_idx = &mut column.selected_task_idx;
 | 
				
			||||||
            let mins = min(self.selected_task_idx() + 1, tasks.len() - 1);
 | 
					        *task_idx = min(*task_idx, column.tasks.len() - 1)
 | 
				
			||||||
            *self.selected_task_idx_mut() = mins;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn select_previous_column(&mut self) {
 | 
					    pub fn select_previous_column(&mut self) -> &Column {
 | 
				
			||||||
        self.selected_column = self.selected_column.saturating_sub(1);
 | 
					        self.project.selected_column_idx = self.project.selected_column_idx.saturating_sub(1);
 | 
				
			||||||
 | 
					        &self.project.columns[self.project.selected_column_idx]
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn select_next_column(&mut self) {
 | 
					    pub fn select_next_column(&mut self) -> &Column {
 | 
				
			||||||
        self.selected_column = min(
 | 
					        self.project.selected_column_idx = min(
 | 
				
			||||||
            self.selected_column + 1,
 | 
					            self.project.selected_column_idx + 1,
 | 
				
			||||||
            self.project.tasks_per_column.len() - 1,
 | 
					            self.project.columns.len() - 1,
 | 
				
			||||||
        )
 | 
					        );
 | 
				
			||||||
 | 
					        &self.project.columns[self.project.selected_column_idx]
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn move_task_previous_column(&mut self) {
 | 
					    pub fn move_task_previous_column(&mut self) {
 | 
				
			||||||
        let tasks = self.get_tasks_in_active_column();
 | 
					        let column = self.project.get_selected_column_mut();
 | 
				
			||||||
        let task_idx = self.selected_task_idx();
 | 
					        if let Some(task) = column.get_selected_task_mut() {
 | 
				
			||||||
        if self.selected_column > 0 && tasks.len() > 0 && task_idx.clone() < tasks.len() {
 | 
					            if self.project.selected_column_idx > 0 {
 | 
				
			||||||
            let task = self.get_tasks_in_active_column_mut().remove(task_idx);
 | 
					                column.tasks.remove(column.selected_task_idx);
 | 
				
			||||||
            *self.selected_task_idx_mut() = self.selected_task_idx().saturating_sub(1);
 | 
					                self.select_previous_column().tasks.push(*task);
 | 
				
			||||||
            self.select_previous_column();
 | 
					 | 
				
			||||||
            let target_tasks = self.get_tasks_in_active_column_mut();
 | 
					 | 
				
			||||||
            target_tasks.push(task);
 | 
					 | 
				
			||||||
            *self.selected_task_idx_mut() = target_tasks.len() - 1;
 | 
					 | 
				
			||||||
                self.project.save();
 | 
					                self.project.save();
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn move_task_next_column(&mut self) {
 | 
					    pub fn move_task_next_column(&mut self) {
 | 
				
			||||||
        let tasks = self.get_tasks_in_active_column();
 | 
					        let column = self.project.get_selected_column();
 | 
				
			||||||
        let task_idx = self.selected_task_idx();
 | 
					        if let Some(task) = column.get_selected_task() {
 | 
				
			||||||
        if self.selected_column < self.project.tasks_per_column.len()
 | 
					            if self.project.selected_column_idx < self.project.columns.len() {
 | 
				
			||||||
            && tasks.len() > 0
 | 
					                column.tasks.remove(column.selected_task_idx);
 | 
				
			||||||
            && task_idx < tasks.len()
 | 
					                self.select_next_column().tasks.push(*task);
 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            let task = self.get_tasks_in_active_column_mut().remove(task_idx);
 | 
					 | 
				
			||||||
            *self.selected_task_idx_mut() = self.selected_task_idx().saturating_sub(1);
 | 
					 | 
				
			||||||
            self.select_next_column();
 | 
					 | 
				
			||||||
            let target_tasks = self.get_tasks_in_active_column_mut();
 | 
					 | 
				
			||||||
            target_tasks.push(task);
 | 
					 | 
				
			||||||
            *self.selected_task_idx_mut() = target_tasks.len() - 1;
 | 
					 | 
				
			||||||
                self.project.save();
 | 
					                self.project.save();
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn move_task_up(&mut self) {
 | 
					    pub fn move_task_up(&mut self) {
 | 
				
			||||||
        let task_idx = self.selected_task_idx();
 | 
					        let column = self.project.get_selected_column();
 | 
				
			||||||
        if task_idx > 0 {
 | 
					        if column.selected_task_idx > 0 {
 | 
				
			||||||
            let tasks = self.get_tasks_in_active_column_mut();
 | 
					            column.tasks.swap(column.selected_task_idx, column.selected_task_idx - 1);
 | 
				
			||||||
            tasks.swap(task_idx, task_idx - 1);
 | 
					            column.selected_task_idx = column.selected_task_idx - 1;
 | 
				
			||||||
            *self.selected_task_idx_mut() = task_idx - 1;
 | 
					 | 
				
			||||||
            self.project.save();
 | 
					            self.project.save();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn move_task_down(&mut self) {
 | 
					    pub fn move_task_down(&mut self) {
 | 
				
			||||||
        let task_idx = self.selected_task_idx();
 | 
					        let column = self.project.get_selected_column();
 | 
				
			||||||
        let tasks = self.get_tasks_in_active_column_mut();
 | 
					        if column.selected_task_idx < column.tasks.len() - 1 {
 | 
				
			||||||
        if task_idx < tasks.len() - 1 {
 | 
					            column.tasks.swap(column.selected_task_idx, column.selected_task_idx + 1);
 | 
				
			||||||
            tasks.swap(task_idx, task_idx + 1);
 | 
					            column.selected_task_idx = column.selected_task_idx + 1;
 | 
				
			||||||
            *self.selected_task_idx_mut() = task_idx + 1;
 | 
					 | 
				
			||||||
            self.project.save();
 | 
					            self.project.save();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -7,13 +7,13 @@ pub fn handle_input(state: &mut AppState) -> Result<(), std::io::Error> {
 | 
				
			|||||||
        match key.code {
 | 
					        match key.code {
 | 
				
			||||||
            KeyCode::Char('q') => state.quit = true,
 | 
					            KeyCode::Char('q') => state.quit = true,
 | 
				
			||||||
            KeyCode::Char('h') |
 | 
					            KeyCode::Char('h') |
 | 
				
			||||||
            KeyCode::Left      => state.select_previous_column(),
 | 
					            KeyCode::Left      => { state.select_previous_column(); },
 | 
				
			||||||
            KeyCode::Char('j') |
 | 
					            KeyCode::Char('j') |
 | 
				
			||||||
            KeyCode::Down      => state.select_next_task(),
 | 
					            KeyCode::Down      => state.select_next_task(),
 | 
				
			||||||
            KeyCode::Char('k') |
 | 
					            KeyCode::Char('k') |
 | 
				
			||||||
            KeyCode::Up        => state.select_previous_task(),
 | 
					            KeyCode::Up        => state.select_previous_task(),
 | 
				
			||||||
            KeyCode::Char('l') |
 | 
					            KeyCode::Char('l') |
 | 
				
			||||||
            KeyCode::Right     => state.select_next_column(),
 | 
					            KeyCode::Right     => { state.select_next_column(); },
 | 
				
			||||||
            KeyCode::Char('<') |
 | 
					            KeyCode::Char('<') |
 | 
				
			||||||
            KeyCode::Char('H') => state.move_task_previous_column(),
 | 
					            KeyCode::Char('H') => state.move_task_previous_column(),
 | 
				
			||||||
            KeyCode::Char('>') |
 | 
					            KeyCode::Char('>') |
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										18
									
								
								src/ui.rs
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								src/ui.rs
									
									
									
									
									
								
							@ -11,20 +11,22 @@ fn draw_tasks<B: Backend>(f: &mut Frame<B>, area: &Rect, state: &AppState) {
 | 
				
			|||||||
        .direction(Direction::Horizontal)
 | 
					        .direction(Direction::Horizontal)
 | 
				
			||||||
        .constraints(
 | 
					        .constraints(
 | 
				
			||||||
            vec![
 | 
					            vec![
 | 
				
			||||||
                Constraint::Percentage(100 / state.project.tasks_per_column.len() as u16);
 | 
					                Constraint::Percentage(100 / state.project.columns.len() as u16);
 | 
				
			||||||
                state.project.tasks_per_column.len()
 | 
					                state.project.columns.len()
 | 
				
			||||||
            ]
 | 
					            ]
 | 
				
			||||||
            .as_ref(),
 | 
					            .as_ref(),
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        .split(*area);
 | 
					        .split(*area);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (i, (status, tasks)) in state.project.tasks_per_column.iter().enumerate() {
 | 
					    for (i, column) in state.project.columns.iter().enumerate() {
 | 
				
			||||||
        let items: Vec<ListItem> = tasks
 | 
					        let items: Vec<ListItem> = column.tasks
 | 
				
			||||||
            .iter()
 | 
					            .iter()
 | 
				
			||||||
            .enumerate()
 | 
					            .enumerate()
 | 
				
			||||||
            .map(|(j, task)| {
 | 
					            .map(|(j, task)| {
 | 
				
			||||||
                let mut style = Style::default();
 | 
					                let mut style = Style::default();
 | 
				
			||||||
                if i == state.selected_column && j == state.selected_task[state.selected_column] {
 | 
					                let col_idx = state.project.selected_column_idx;
 | 
				
			||||||
 | 
					                let task_idx = state.project.get_selected_column().selected_task_idx;
 | 
				
			||||||
 | 
					                if i == col_idx && j == task_idx {
 | 
				
			||||||
                    style = style.fg(Color::White).add_modifier(Modifier::BOLD);
 | 
					                    style = style.fg(Color::White).add_modifier(Modifier::BOLD);
 | 
				
			||||||
                } else {
 | 
					                } else {
 | 
				
			||||||
                    style = style.fg(Color::White);
 | 
					                    style = style.fg(Color::White);
 | 
				
			||||||
@ -35,10 +37,10 @@ fn draw_tasks<B: Backend>(f: &mut Frame<B>, area: &Rect, state: &AppState) {
 | 
				
			|||||||
            })
 | 
					            })
 | 
				
			||||||
            .collect();
 | 
					            .collect();
 | 
				
			||||||
        let mut style = Style::default();
 | 
					        let mut style = Style::default();
 | 
				
			||||||
        if i == state.selected_column {
 | 
					        if i == state.project.selected_column_idx {
 | 
				
			||||||
            style = style.fg(Color::Green);
 | 
					            style = style.fg(Color::Green);
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        let mut s = Span::raw(format!("{:?}", status));
 | 
					        let mut s = Span::raw(format!("{:?}", column.name));
 | 
				
			||||||
        s.style = Style::default()
 | 
					        s.style = Style::default()
 | 
				
			||||||
            .add_modifier(Modifier::BOLD | Modifier::ITALIC | Modifier::UNDERLINED)
 | 
					            .add_modifier(Modifier::BOLD | Modifier::ITALIC | Modifier::UNDERLINED)
 | 
				
			||||||
            .fg(Color::White);
 | 
					            .fg(Color::White);
 | 
				
			||||||
@ -50,7 +52,7 @@ fn draw_tasks<B: Backend>(f: &mut Frame<B>, area: &Rect, state: &AppState) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
fn draw_task_info<B: Backend>(f: &mut Frame<B>, area: &Rect, state: &AppState) {
 | 
					fn draw_task_info<B: Backend>(f: &mut Frame<B>, area: &Rect, state: &AppState) {
 | 
				
			||||||
    let block = Block::default().title("TASK INFO").borders(Borders::ALL);
 | 
					    let block = Block::default().title("TASK INFO").borders(Borders::ALL);
 | 
				
			||||||
    if let Some(task) = state.get_selected_task() {
 | 
					    if let Some(task) = state.project.get_selected_column().get_selected_task() {
 | 
				
			||||||
        let p = Paragraph::new(task.description.as_str())
 | 
					        let p = Paragraph::new(task.description.as_str())
 | 
				
			||||||
            .block(block)
 | 
					            .block(block)
 | 
				
			||||||
            .wrap(Wrap { trim: true });
 | 
					            .wrap(Wrap { trim: true });
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user