Compare commits
No commits in common. "1b0f7dca097e906f9ac604a134a02c21486441b1" and "721c200b97d008bc999d7e08f0e6a4f2d9b5fd94" have entirely different histories.
1b0f7dca09
...
721c200b97
17
src/kinds.rs
17
src/kinds.rs
|
@ -3,18 +3,16 @@ use log::info;
|
||||||
use nostr_sdk::{Alphabet, EventBuilder, EventId, Kind, Tag, TagStandard};
|
use nostr_sdk::{Alphabet, EventBuilder, EventId, Kind, Tag, TagStandard};
|
||||||
use nostr_sdk::TagStandard::Hashtag;
|
use nostr_sdk::TagStandard::Hashtag;
|
||||||
|
|
||||||
use crate::task::{MARKER_PARENT, State};
|
use crate::task::State;
|
||||||
|
|
||||||
pub const METADATA_KIND: u16 = 0;
|
pub const METADATA_KIND: u16 = 0;
|
||||||
pub const NOTE_KIND: u16 = 1;
|
pub const NOTE_KIND: u16 = 1;
|
||||||
pub const TASK_KIND: u16 = 1621;
|
pub const TASK_KIND: u16 = 1621;
|
||||||
pub const TRACKING_KIND: u16 = 1650;
|
pub const TRACKING_KIND: u16 = 1650;
|
||||||
pub const KINDS: [u16; 3] = [
|
pub const KINDS: [u16; 9] = [
|
||||||
METADATA_KIND,
|
METADATA_KIND,
|
||||||
NOTE_KIND,
|
NOTE_KIND,
|
||||||
TASK_KIND,
|
TASK_KIND,
|
||||||
];
|
|
||||||
pub const PROP_KINDS: [u16; 6] = [
|
|
||||||
TRACKING_KIND,
|
TRACKING_KIND,
|
||||||
State::Open as u16,
|
State::Open as u16,
|
||||||
State::Done as u16,
|
State::Done as u16,
|
||||||
|
@ -32,7 +30,7 @@ Immutable:
|
||||||
- `parentid` - unique task id of the parent, if any
|
- `parentid` - unique task id of the parent, if any
|
||||||
- `name` - initial name of the task
|
- `name` - initial name of the task
|
||||||
- `created` - task creation timestamp
|
- `created` - task creation timestamp
|
||||||
- `author` - name or abbreviated key of the task creator
|
- `author` - name of the task creator
|
||||||
Task:
|
Task:
|
||||||
- `status` - pure task status
|
- `status` - pure task status
|
||||||
- `hashtags` - list of hashtags set for the task
|
- `hashtags` - list of hashtags set for the task
|
||||||
|
@ -100,16 +98,13 @@ fn format_tag(tag: &Tag) -> String {
|
||||||
match tag.as_standardized() {
|
match tag.as_standardized() {
|
||||||
Some(TagStandard::Event {
|
Some(TagStandard::Event {
|
||||||
event_id,
|
event_id,
|
||||||
marker,
|
|
||||||
..
|
..
|
||||||
}) => format!("{}: {:.8}", marker.as_ref().map(|m| m.to_string()).unwrap_or(MARKER_PARENT.to_string()), event_id),
|
}) => format!("Parent: {}", event_id.to_string()[..8].to_string()),
|
||||||
Some(TagStandard::PublicKey {
|
Some(TagStandard::PublicKey {
|
||||||
public_key,
|
public_key,
|
||||||
alias,
|
|
||||||
..
|
..
|
||||||
}) => format!("Key{}: {:.8}", public_key.to_string(), alias.as_ref().map(|s| format!(" {s}")).unwrap_or_default()),
|
}) => format!("Key: {}", public_key.to_string()[..8].to_string()),
|
||||||
Some(TagStandard::Hashtag(content)) =>
|
Some(TagStandard::Hashtag(content)) => format!("#{content}"),
|
||||||
format!("#{content}"),
|
|
||||||
_ => tag.content().map_or_else(
|
_ => tag.content().map_or_else(
|
||||||
|| format!("Kind {}", tag.kind()),
|
|| format!("Kind {}", tag.kind()),
|
||||||
|content| content.to_string(),
|
|content| content.to_string(),
|
||||||
|
|
27
src/main.rs
27
src/main.rs
|
@ -23,7 +23,7 @@ use regex::Regex;
|
||||||
use xdg::BaseDirectories;
|
use xdg::BaseDirectories;
|
||||||
|
|
||||||
use crate::helpers::*;
|
use crate::helpers::*;
|
||||||
use crate::kinds::{KINDS, PROP_KINDS, PROPERTY_COLUMNS, TRACKING_KIND};
|
use crate::kinds::{KINDS, PROPERTY_COLUMNS, TRACKING_KIND};
|
||||||
use crate::task::{MARKER_DEPENDS, MARKER_PARENT, State};
|
use crate::task::{MARKER_DEPENDS, MARKER_PARENT, State};
|
||||||
use crate::tasks::{PropertyCollection, StateFilter, Tasks};
|
use crate::tasks::{PropertyCollection, StateFilter, Tasks};
|
||||||
|
|
||||||
|
@ -180,19 +180,14 @@ async fn main() {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
let sub1 = client.subscribe(vec![
|
let sub_id = client.subscribe(vec![
|
||||||
Filter::new().kinds(KINDS.into_iter().map(|k| Kind::from(k)))
|
Filter::new().kinds(KINDS.into_iter().map(|k| Kind::from(k)))
|
||||||
], None).await;
|
], None).await;
|
||||||
info!("Subscribed to tasks with {:?}", sub1);
|
info!("Subscribed with {:?}", sub_id);
|
||||||
|
|
||||||
let mut notifications = client.notifications();
|
let mut notifications = client.notifications();
|
||||||
client.connect().await;
|
client.connect().await;
|
||||||
|
|
||||||
let sub2 = client.subscribe(vec![
|
|
||||||
Filter::new().kinds(PROP_KINDS.into_iter().map(|k| Kind::from(k)))
|
|
||||||
], None).await;
|
|
||||||
info!("Subscribed to updates with {:?}", sub2);
|
|
||||||
|
|
||||||
let (tx, rx) = mpsc::channel::<MostrMessage>();
|
let (tx, rx) = mpsc::channel::<MostrMessage>();
|
||||||
let tasks_for_url = |url: Option<Url>| Tasks::from(url, &tx, &keys);
|
let tasks_for_url = |url: Option<Url>| Tasks::from(url, &tx, &keys);
|
||||||
let mut relays: HashMap<Url, Tasks> =
|
let mut relays: HashMap<Url, Tasks> =
|
||||||
|
@ -379,12 +374,11 @@ async fn main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
Some('@') => {
|
Some('@') => {
|
||||||
let key = arg.and_then(|a| PublicKey::from_str(a).ok()).unwrap_or_else(|| keys.public_key());
|
let author = arg.and_then(|a| PublicKey::from_str(a).ok()).unwrap_or_else(|| keys.public_key());
|
||||||
let author = tasks.get_author(&key);
|
|
||||||
info!("Filtering for events by {author}");
|
info!("Filtering for events by {author}");
|
||||||
tasks.set_filter(
|
tasks.set_filter(
|
||||||
tasks.filtered_tasks(tasks.get_position_ref())
|
tasks.filtered_tasks(tasks.get_position_ref())
|
||||||
.filter(|t| t.event.pubkey == key)
|
.filter(|t| t.event.pubkey == author)
|
||||||
.map(|t| t.event.id)
|
.map(|t| t.event.id)
|
||||||
.collect()
|
.collect()
|
||||||
)
|
)
|
||||||
|
@ -473,13 +467,10 @@ async fn main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(')') => {
|
Some(')') => {
|
||||||
match arg {
|
tasks.move_to(None);
|
||||||
None => tasks.move_to(None),
|
if let Some(arg) = arg {
|
||||||
Some(arg) => {
|
if !tasks.track_from(arg) {
|
||||||
if parse_tracking_stamp(arg).map(|stamp| tasks.track_at(stamp, None)).is_none() {
|
continue;
|
||||||
// So the error message is not covered up
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
36
src/tasks.rs
36
src/tasks.rs
|
@ -119,21 +119,19 @@ impl Tasks {
|
||||||
tasks: Default::default(),
|
tasks: Default::default(),
|
||||||
history: Default::default(),
|
history: Default::default(),
|
||||||
users: Default::default(),
|
users: Default::default(),
|
||||||
properties: [
|
properties: vec![
|
||||||
"author",
|
"state".into(),
|
||||||
"state",
|
"rtime".into(),
|
||||||
"rtime",
|
"hashtags".into(),
|
||||||
"hashtags",
|
"rpath".into(),
|
||||||
"rpath",
|
"desc".into(),
|
||||||
"desc",
|
],
|
||||||
].into_iter().map(|s| s.to_string()).collect(),
|
sorting: VecDeque::from([
|
||||||
sorting: [
|
"state".into(),
|
||||||
"author",
|
"hashtags".into(),
|
||||||
"state",
|
"rtime".into(),
|
||||||
"hashtags",
|
"name".into(),
|
||||||
"rtime",
|
]),
|
||||||
"name",
|
|
||||||
].into_iter().map(|s| s.to_string()).collect(),
|
|
||||||
view: Default::default(),
|
view: Default::default(),
|
||||||
tags: Default::default(),
|
tags: Default::default(),
|
||||||
tags_excluded: Default::default(),
|
tags_excluded: Default::default(),
|
||||||
|
@ -214,11 +212,11 @@ impl Tasks {
|
||||||
} else {
|
} else {
|
||||||
format_stamp(end, "%H:%M")
|
format_stamp(end, "%H:%M")
|
||||||
},
|
},
|
||||||
self.get_author(key)))
|
key))
|
||||||
}
|
}
|
||||||
iter.into_buffer()
|
iter.into_buffer()
|
||||||
.for_each(|(stamp, _)|
|
.for_each(|(stamp, _)|
|
||||||
vec.push(format!("{} started by {}", local_datetimestamp(stamp), self.get_author(key))));
|
vec.push(format!("{} started by {}", local_datetimestamp(stamp), key)));
|
||||||
vec
|
vec
|
||||||
}).sorted_unstable(); // TODO sorting depends on timestamp format - needed to interleave different people
|
}).sorted_unstable(); // TODO sorting depends on timestamp format - needed to interleave different people
|
||||||
(format!("Times Tracked on {:?}", self.get_task_title(&id)), Box::from(history))
|
(format!("Times Tracked on {:?}", self.get_task_title(&id)), Box::from(history))
|
||||||
|
@ -427,7 +425,7 @@ impl Tasks {
|
||||||
writeln!(lock, "{}\n{}", label.italic(), times_recent.join("\n"))?;
|
writeln!(lock, "{}\n{}", label.italic(), times_recent.join("\n"))?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO proper column alignment
|
// TODO proper column alignment
|
||||||
// TODO hide empty columns
|
// TODO hide empty columns
|
||||||
writeln!(lock, "{}", self.properties.join("\t").bold())?;
|
writeln!(lock, "{}", self.properties.join("\t").bold())?;
|
||||||
|
@ -504,7 +502,7 @@ impl Tasks {
|
||||||
pub(crate) fn get_author(&self, pubkey: &PublicKey) -> String {
|
pub(crate) fn get_author(&self, pubkey: &PublicKey) -> String {
|
||||||
self.users.get(pubkey)
|
self.users.get(pubkey)
|
||||||
.and_then(|m| m.name.clone())
|
.and_then(|m| m.name.clone())
|
||||||
.unwrap_or_else(|| format!("{:.6}", pubkey.to_string()))
|
.unwrap_or_else(|| pubkey.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Movement and Selection
|
// Movement and Selection
|
||||||
|
|
Loading…
Reference in New Issue