Compare commits

..

No commits in common. "1b0f7dca097e906f9ac604a134a02c21486441b1" and "721c200b97d008bc999d7e08f0e6a4f2d9b5fd94" have entirely different histories.

3 changed files with 32 additions and 48 deletions

View File

@ -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(),

View File

@ -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
}
} }
} }
} }

View File

@ -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))
@ -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