Compare commits
5 Commits
721c200b97
...
1b0f7dca09
Author | SHA1 | Date |
---|---|---|
xeruf | 1b0f7dca09 | |
xeruf | f4cff3d702 | |
xeruf | f8a4777f71 | |
xeruf | 0296556bcd | |
xeruf | c64a1fa051 |
17
src/kinds.rs
17
src/kinds.rs
|
@ -3,16 +3,18 @@ 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::State;
|
use crate::task::{MARKER_PARENT, 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; 9] = [
|
pub const KINDS: [u16; 3] = [
|
||||||
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,
|
||||||
|
@ -30,7 +32,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 of the task creator
|
- `author` - name or abbreviated key 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
|
||||||
|
@ -98,13 +100,16 @@ 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!("Parent: {}", event_id.to_string()[..8].to_string()),
|
}) => format!("{}: {:.8}", marker.as_ref().map(|m| m.to_string()).unwrap_or(MARKER_PARENT.to_string()), event_id),
|
||||||
Some(TagStandard::PublicKey {
|
Some(TagStandard::PublicKey {
|
||||||
public_key,
|
public_key,
|
||||||
|
alias,
|
||||||
..
|
..
|
||||||
}) => format!("Key: {}", public_key.to_string()[..8].to_string()),
|
}) => format!("Key{}: {:.8}", public_key.to_string(), alias.as_ref().map(|s| format!(" {s}")).unwrap_or_default()),
|
||||||
Some(TagStandard::Hashtag(content)) => format!("#{content}"),
|
Some(TagStandard::Hashtag(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, PROPERTY_COLUMNS, TRACKING_KIND};
|
use crate::kinds::{KINDS, PROP_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,14 +180,19 @@ async fn main() {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
let sub_id = client.subscribe(vec![
|
let sub1 = 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 with {:?}", sub_id);
|
info!("Subscribed to tasks with {:?}", sub1);
|
||||||
|
|
||||||
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> =
|
||||||
|
@ -374,11 +379,12 @@ async fn main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
Some('@') => {
|
Some('@') => {
|
||||||
let author = arg.and_then(|a| PublicKey::from_str(a).ok()).unwrap_or_else(|| keys.public_key());
|
let key = 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 == author)
|
.filter(|t| t.event.pubkey == key)
|
||||||
.map(|t| t.event.id)
|
.map(|t| t.event.id)
|
||||||
.collect()
|
.collect()
|
||||||
)
|
)
|
||||||
|
@ -467,10 +473,13 @@ async fn main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(')') => {
|
Some(')') => {
|
||||||
tasks.move_to(None);
|
match arg {
|
||||||
if let Some(arg) = arg {
|
None => tasks.move_to(None),
|
||||||
if !tasks.track_from(arg) {
|
Some(arg) => {
|
||||||
continue;
|
if parse_tracking_stamp(arg).map(|stamp| tasks.track_at(stamp, None)).is_none() {
|
||||||
|
// So the error message is not covered up
|
||||||
|
continue
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
34
src/tasks.rs
34
src/tasks.rs
|
@ -119,19 +119,21 @@ impl Tasks {
|
||||||
tasks: Default::default(),
|
tasks: Default::default(),
|
||||||
history: Default::default(),
|
history: Default::default(),
|
||||||
users: Default::default(),
|
users: Default::default(),
|
||||||
properties: vec![
|
properties: [
|
||||||
"state".into(),
|
"author",
|
||||||
"rtime".into(),
|
"state",
|
||||||
"hashtags".into(),
|
"rtime",
|
||||||
"rpath".into(),
|
"hashtags",
|
||||||
"desc".into(),
|
"rpath",
|
||||||
],
|
"desc",
|
||||||
sorting: VecDeque::from([
|
].into_iter().map(|s| s.to_string()).collect(),
|
||||||
"state".into(),
|
sorting: [
|
||||||
"hashtags".into(),
|
"author",
|
||||||
"rtime".into(),
|
"state",
|
||||||
"name".into(),
|
"hashtags",
|
||||||
]),
|
"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(),
|
||||||
|
@ -212,11 +214,11 @@ impl Tasks {
|
||||||
} else {
|
} else {
|
||||||
format_stamp(end, "%H:%M")
|
format_stamp(end, "%H:%M")
|
||||||
},
|
},
|
||||||
key))
|
self.get_author(key)))
|
||||||
}
|
}
|
||||||
iter.into_buffer()
|
iter.into_buffer()
|
||||||
.for_each(|(stamp, _)|
|
.for_each(|(stamp, _)|
|
||||||
vec.push(format!("{} started by {}", local_datetimestamp(stamp), key)));
|
vec.push(format!("{} started by {}", local_datetimestamp(stamp), self.get_author(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))
|
||||||
|
@ -502,7 +504,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(|| pubkey.to_string())
|
.unwrap_or_else(|| format!("{:.6}", pubkey.to_string()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Movement and Selection
|
// Movement and Selection
|
||||||
|
|
Loading…
Reference in New Issue