feat: enable setting view depth
This commit is contained in:
parent
87cdecbeee
commit
6ed2299ee0
67
src/main.rs
67
src/main.rs
|
@ -181,10 +181,6 @@ async fn main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
if input.chars().nth(1) == Some(':') {
|
|
||||||
tasks.recursive = !tasks.recursive;
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
let prop = &input[1..];
|
let prop = &input[1..];
|
||||||
let pos = tasks.properties.iter().position(|s| s == &prop);
|
let pos = tasks.properties.iter().position(|s| s == &prop);
|
||||||
match pos {
|
match pos {
|
||||||
|
@ -217,37 +213,42 @@ async fn main() {
|
||||||
pos = tasks.parent(pos);
|
pos = tasks.parent(pos);
|
||||||
}
|
}
|
||||||
let slice = &input[dots..];
|
let slice = &input[dots..];
|
||||||
if !slice.is_empty() {
|
if slice.is_empty() {
|
||||||
pos = EventId::parse(slice).ok().or_else(|| {
|
tasks.move_to(pos);
|
||||||
// TODO check what is more intuitive:
|
continue;
|
||||||
// currently resets filters before filtering again, maybe keep them
|
}
|
||||||
tasks.move_to(pos);
|
if let Ok(depth) = slice.parse::<i8>() {
|
||||||
let filtered: Vec<EventId> = tasks
|
tasks.move_to(pos);
|
||||||
.current_tasks()
|
tasks.depth = depth;
|
||||||
.iter()
|
continue;
|
||||||
.filter(|t| t.event.content.starts_with(slice))
|
}
|
||||||
.map(|t| t.event.id)
|
pos = EventId::parse(slice).ok().or_else(|| {
|
||||||
.collect();
|
// TODO check what is more intuitive:
|
||||||
match filtered.len() {
|
// currently resets filters before filtering again, maybe keep them
|
||||||
0 => {
|
tasks.move_to(pos);
|
||||||
// No match, new task
|
let filtered: Vec<EventId> = tasks
|
||||||
tasks.make_task(slice)
|
.current_tasks()
|
||||||
}
|
.into_iter()
|
||||||
1 => {
|
.filter(|t| t.event.content.starts_with(slice))
|
||||||
// One match, activate
|
.map(|t| t.event.id)
|
||||||
Some(filtered.first().unwrap().clone())
|
.collect();
|
||||||
}
|
match filtered.len() {
|
||||||
_ => {
|
0 => {
|
||||||
// Multiple match, filter
|
// No match, new task
|
||||||
tasks.set_filter(filtered);
|
tasks.make_task(slice)
|
||||||
None
|
}
|
||||||
}
|
1 => {
|
||||||
|
// One match, activate
|
||||||
|
Some(filtered.first().unwrap().clone())
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
// Multiple match, filter
|
||||||
|
tasks.set_filter(filtered);
|
||||||
|
None
|
||||||
}
|
}
|
||||||
});
|
|
||||||
if pos != None {
|
|
||||||
tasks.move_to(pos);
|
|
||||||
}
|
}
|
||||||
} else {
|
});
|
||||||
|
if pos != None {
|
||||||
tasks.move_to(pos);
|
tasks.move_to(pos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
99
src/tasks.rs
99
src/tasks.rs
|
@ -1,7 +1,8 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::iter::once;
|
use std::iter::once;
|
||||||
|
use std::sync::mpsc;
|
||||||
|
|
||||||
use nostr_sdk::{Event, EventBuilder, EventId, Kind, Tag};
|
use nostr_sdk::{Event, EventBuilder, EventId, Keys, Kind, Tag};
|
||||||
|
|
||||||
use crate::{EventSender, TASK_KIND};
|
use crate::{EventSender, TASK_KIND};
|
||||||
use crate::task::{State, Task};
|
use crate::task::{State, Task};
|
||||||
|
@ -12,8 +13,10 @@ pub(crate) struct Tasks {
|
||||||
tasks: TaskMap,
|
tasks: TaskMap,
|
||||||
/// The task properties currently visible
|
/// The task properties currently visible
|
||||||
pub(crate) properties: Vec<String>,
|
pub(crate) properties: Vec<String>,
|
||||||
// TODO: plain, recursive, only leafs
|
/// Negative: Only Leaf nodes
|
||||||
pub(crate) recursive: bool,
|
/// Zero: Only Active node
|
||||||
|
/// Positive: Go down the respective level
|
||||||
|
pub(crate) depth: i8,
|
||||||
|
|
||||||
/// The task currently selected.
|
/// The task currently selected.
|
||||||
position: Option<EventId>,
|
position: Option<EventId>,
|
||||||
|
@ -30,7 +33,7 @@ impl Tasks {
|
||||||
properties: vec!["id".into(), "name".into(), "state".into(), "ttime".into()],
|
properties: vec!["id".into(), "name".into(), "state".into(), "ttime".into()],
|
||||||
position: None,
|
position: None,
|
||||||
view: Default::default(),
|
view: Default::default(),
|
||||||
recursive: false,
|
depth: 1,
|
||||||
sender
|
sender
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,28 +58,45 @@ impl Tasks {
|
||||||
pub(crate) fn set_filter(&mut self, view: Vec<EventId>) {
|
pub(crate) fn set_filter(&mut self, view: Vec<EventId>) {
|
||||||
self.view = view
|
self.view = view
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_tasks<'a>(&self, iter: impl IntoIterator<Item=&'a EventId>) -> Vec<&Task> {
|
fn resolve_tasks<'a>(&self, iter: impl IntoIterator<Item=&'a EventId>) -> Vec<&Task> {
|
||||||
|
self.resolve_tasks_rec(iter, self.depth)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolve_tasks_rec<'a>(&self, iter: impl IntoIterator<Item=&'a EventId>, depth: i8) -> Vec<&Task> {
|
||||||
iter.into_iter().filter_map(|id| self.tasks.get(&id)).flat_map(|task| {
|
iter.into_iter().filter_map(|id| self.tasks.get(&id)).flat_map(|task| {
|
||||||
if self.recursive {
|
let new_depth = depth - 1;
|
||||||
self.resolve_tasks(task.children.iter()).into_iter().chain(once(task)).collect()
|
if new_depth < 0 {
|
||||||
|
let tasks = self.resolve_tasks_rec(task.children.iter(), new_depth).into_iter().collect::<Vec<&Task>>();
|
||||||
|
if tasks.is_empty() {
|
||||||
|
vec![task]
|
||||||
|
} else {
|
||||||
|
tasks
|
||||||
|
}
|
||||||
|
} else if new_depth > 0 {
|
||||||
|
self.resolve_tasks_rec(task.children.iter(), new_depth).into_iter().chain(once(task)).collect()
|
||||||
} else {
|
} else {
|
||||||
vec![task]
|
vec![task]
|
||||||
}
|
}
|
||||||
}).collect()
|
}).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn current_tasks(&self) -> Vec<&Task> {
|
pub(crate) fn current_tasks(&self) -> Vec<&Task> {
|
||||||
|
if self.depth == 0 {
|
||||||
|
return self.position.and_then(|id| self.tasks.get(&id)).into_iter().collect();
|
||||||
|
}
|
||||||
let res: Vec<&Task> = self.resolve_tasks(self.view.iter());
|
let res: Vec<&Task> = self.resolve_tasks(self.view.iter());
|
||||||
if res.len() > 0 {
|
if res.len() > 0 {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
self.position.map_or_else(
|
self.position.map_or_else(
|
||||||
|| {
|
|| {
|
||||||
if self.recursive {
|
if self.depth > 8 {
|
||||||
self.tasks.values().collect()
|
self.tasks.values().collect()
|
||||||
} else {
|
} else if self.depth == 1 {
|
||||||
self.tasks.values().filter(|t| t.parent_id() == None).collect()
|
self.tasks.values().filter(|t| t.parent_id() == None).collect()
|
||||||
|
} else {
|
||||||
|
self.resolve_tasks(self.tasks.values().filter(|t| t.parent_id() == None).map(|t| &t.event.id))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|p| self.tasks.get(&p).map_or(Vec::new(), |t| self.resolve_tasks(t.children.iter())),
|
|p| self.tasks.get(&p).map_or(Vec::new(), |t| self.resolve_tasks(t.children.iter())),
|
||||||
|
@ -251,3 +271,62 @@ impl<'a> Iterator for ParentIterator<'a> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_depth() {
|
||||||
|
let (tx, rx) = mpsc::channel();
|
||||||
|
let mut tasks = Tasks::from(EventSender {
|
||||||
|
tx,
|
||||||
|
keys: Keys::generate(),
|
||||||
|
});
|
||||||
|
let t1 = tasks.make_task("t1");
|
||||||
|
assert_eq!(tasks.depth, 1);
|
||||||
|
assert_eq!(tasks.current_tasks().len(), 1);
|
||||||
|
tasks.depth = 0;
|
||||||
|
assert_eq!(tasks.current_tasks().len(), 0);
|
||||||
|
|
||||||
|
tasks.move_to(t1);
|
||||||
|
tasks.depth = 2;
|
||||||
|
assert_eq!(tasks.current_tasks().len(), 0);
|
||||||
|
let t2 = tasks.make_task("t2");
|
||||||
|
assert_eq!(tasks.current_tasks().len(), 1);
|
||||||
|
let t3 = tasks.make_task("t3");
|
||||||
|
assert_eq!(tasks.current_tasks().len(), 2);
|
||||||
|
|
||||||
|
tasks.move_to(t2);
|
||||||
|
assert_eq!(tasks.current_tasks().len(), 0);
|
||||||
|
let t4 = tasks.make_task("t4");
|
||||||
|
assert_eq!(tasks.current_tasks().len(), 1);
|
||||||
|
tasks.depth = 2;
|
||||||
|
assert_eq!(tasks.current_tasks().len(), 1);
|
||||||
|
tasks.depth = -1;
|
||||||
|
assert_eq!(tasks.current_tasks().len(), 1);
|
||||||
|
|
||||||
|
tasks.move_to(t1);
|
||||||
|
assert_eq!(tasks.current_tasks().len(), 2);
|
||||||
|
tasks.depth = 2;
|
||||||
|
assert_eq!(tasks.current_tasks().len(), 3);
|
||||||
|
tasks.set_filter(vec![t2.unwrap()]);
|
||||||
|
assert_eq!(tasks.current_tasks().len(), 2);
|
||||||
|
tasks.depth = 1;
|
||||||
|
assert_eq!(tasks.current_tasks().len(), 1);
|
||||||
|
tasks.depth = -1;
|
||||||
|
assert_eq!(tasks.current_tasks().len(), 1);
|
||||||
|
tasks.set_filter(vec![t2.unwrap(), t3.unwrap()]);
|
||||||
|
assert_eq!(tasks.current_tasks().len(), 2);
|
||||||
|
tasks.depth = 2;
|
||||||
|
assert_eq!(tasks.current_tasks().len(), 3);
|
||||||
|
tasks.depth = 1;
|
||||||
|
assert_eq!(tasks.current_tasks().len(), 2);
|
||||||
|
|
||||||
|
tasks.move_to(None);
|
||||||
|
assert_eq!(tasks.current_tasks().len(), 1);
|
||||||
|
tasks.depth = 2;
|
||||||
|
assert_eq!(tasks.current_tasks().len(), 3);
|
||||||
|
tasks.depth = 3;
|
||||||
|
assert_eq!(tasks.current_tasks().len(), 4);
|
||||||
|
tasks.depth = 9;
|
||||||
|
assert_eq!(tasks.current_tasks().len(), 4);
|
||||||
|
tasks.depth = -1;
|
||||||
|
assert_eq!(tasks.current_tasks().len(), 2);
|
||||||
|
}
|
Loading…
Reference in New Issue