Compare commits

..

5 Commits

3 changed files with 48 additions and 32 deletions

View File

@ -3,16 +3,18 @@ use log::info;
use nostr_sdk::{Alphabet, EventBuilder, EventId, Kind, Tag, TagStandard};
use nostr_sdk::TagStandard::Hashtag;
use crate::task::State;
use crate::task::{MARKER_PARENT, State};
pub const METADATA_KIND: u16 = 0;
pub const NOTE_KIND: u16 = 1;
pub const TASK_KIND: u16 = 1621;
pub const TRACKING_KIND: u16 = 1650;
pub const KINDS: [u16; 9] = [
pub const KINDS: [u16; 3] = [
METADATA_KIND,
NOTE_KIND,
TASK_KIND,
];
pub const PROP_KINDS: [u16; 6] = [
TRACKING_KIND,
State::Open as u16,
State::Done as u16,
@ -30,7 +32,7 @@ Immutable:
- `parentid` - unique task id of the parent, if any
- `name` - initial name of the task
- `created` - task creation timestamp
- `author` - name of the task creator
- `author` - name or abbreviated key of the task creator
Task:
- `status` - pure task status
- `hashtags` - list of hashtags set for the task
@ -98,13 +100,16 @@ fn format_tag(tag: &Tag) -> String {
match tag.as_standardized() {
Some(TagStandard::Event {
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 {
public_key,
alias,
..
}) => format!("Key: {}", public_key.to_string()[..8].to_string()),
Some(TagStandard::Hashtag(content)) => format!("#{content}"),
}) => format!("Key{}: {:.8}", public_key.to_string(), alias.as_ref().map(|s| format!(" {s}")).unwrap_or_default()),
Some(TagStandard::Hashtag(content)) =>
format!("#{content}"),
_ => tag.content().map_or_else(
|| format!("Kind {}", tag.kind()),
|content| content.to_string(),

View File

@ -23,7 +23,7 @@ use regex::Regex;
use xdg::BaseDirectories;
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::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)))
], None).await;
info!("Subscribed with {:?}", sub_id);
info!("Subscribed to tasks with {:?}", sub1);
let mut notifications = client.notifications();
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 tasks_for_url = |url: Option<Url>| Tasks::from(url, &tx, &keys);
let mut relays: HashMap<Url, Tasks> =
@ -374,11 +379,12 @@ async fn main() {
}
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}");
tasks.set_filter(
tasks.filtered_tasks(tasks.get_position_ref())
.filter(|t| t.event.pubkey == author)
.filter(|t| t.event.pubkey == key)
.map(|t| t.event.id)
.collect()
)
@ -467,10 +473,13 @@ async fn main() {
}
Some(')') => {
tasks.move_to(None);
if let Some(arg) = arg {
if !tasks.track_from(arg) {
continue;
match arg {
None => tasks.move_to(None),
Some(arg) => {
if parse_tracking_stamp(arg).map(|stamp| tasks.track_at(stamp, None)).is_none() {
// So the error message is not covered up
continue
}
}
}
}

View File

@ -119,19 +119,21 @@ impl Tasks {
tasks: Default::default(),
history: Default::default(),
users: Default::default(),
properties: vec![
"state".into(),
"rtime".into(),
"hashtags".into(),
"rpath".into(),
"desc".into(),
],
sorting: VecDeque::from([
"state".into(),
"hashtags".into(),
"rtime".into(),
"name".into(),
]),
properties: [
"author",
"state",
"rtime",
"hashtags",
"rpath",
"desc",
].into_iter().map(|s| s.to_string()).collect(),
sorting: [
"author",
"state",
"hashtags",
"rtime",
"name",
].into_iter().map(|s| s.to_string()).collect(),
view: Default::default(),
tags: Default::default(),
tags_excluded: Default::default(),
@ -212,11 +214,11 @@ impl Tasks {
} else {
format_stamp(end, "%H:%M")
},
key))
self.get_author(key)))
}
iter.into_buffer()
.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
}).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))
@ -502,7 +504,7 @@ impl Tasks {
pub(crate) fn get_author(&self, pubkey: &PublicKey) -> String {
self.users.get(pubkey)
.and_then(|m| m.name.clone())
.unwrap_or_else(|| pubkey.to_string())
.unwrap_or_else(|| format!("{:.6}", pubkey.to_string()))
}
// Movement and Selection