Skip to content

Commit

Permalink
feat: allow only getting cards of a certain tag
Browse files Browse the repository at this point in the history
  • Loading branch information
BrewingWeasel committed Jan 14, 2024
1 parent 4720d21 commit abe0e2f
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 35 deletions.
1 change: 1 addition & 0 deletions shared/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ pub struct NoteToWordHandling {
pub field_to_use: String,
pub remove_everything_in_parens: bool,
pub only_first_word_or_line: bool,
pub tags_wanted: Vec<String>,
}

#[derive(Deserialize, Serialize, Clone)]
Expand Down
81 changes: 47 additions & 34 deletions src-tauri/src/ankiconnect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,27 @@ pub async fn get_anki_card_statuses(
original_words: &mut HashMap<String, WordInfo>,
days_passed: i64,
) -> Result<(), String> {
let find_cards_query = format!("deck:{deck} rated:{days_passed}"); // TODO: only check cards reviewed since last
// check
println!("getting anki card statuses");
let find_cards_query = format!("\"deck:{deck}\""); // TODO: only check cards reviewed since last
// check with rated:{days_passed} but only when new decks haven't been added

let cards = get_card_or_note_vals("findCards", json!({ "query": find_cards_query })).await?;
let intervals = get_card_or_note_vals("getIntervals", json!({ "cards": &cards })).await?;
let notes = get_card_or_note_vals("cardsToNotes", json!({ "cards": &cards })).await?;

let words = get_words_from_notes(notes, note_handling).await?;
for (word, interval) in words.into_iter().zip(intervals) {
let res = generic_anki_connect_action("notesInfo", json!({ "notes": notes })).await;
let notes_info = Into::<Result<Vec<NoteInfo>, String>>::into(
res.json::<AnkiResult<Vec<NoteInfo>>>().await.unwrap(),
)?;

//let words = get_words_from_notes(notes, note_handling).await?;
for ((note, interval), note_info) in notes.into_iter().zip(intervals).zip(notes_info) {
let Ok(Some(word)) = get_word_from_note(note, note_info, note_handling).await else {
continue;
};

println!("word: {} interval: {interval}", word);

let rating = if interval <= 1 {
0
} else if interval <= 4 {
Expand Down Expand Up @@ -103,48 +115,49 @@ async fn generic_anki_connect_action(action: &str, data: Value) -> Response {
.unwrap()
}

async fn get_card_or_note_vals(action: &str, data: Value) -> Result<Vec<usize>, String> {
async fn get_card_or_note_vals(action: &str, data: Value) -> Result<Vec<isize>, String> {
let res = generic_anki_connect_action(action, data).await;
res.json::<AnkiResult<Vec<usize>>>().await.unwrap().into()
res.json::<AnkiResult<Vec<isize>>>().await.unwrap().into()
}

async fn get_words_from_notes(
notes: Vec<usize>,
async fn get_word_from_note(
note_id: isize,
note: NoteInfo,
templates: &HashMap<String, NoteToWordHandling>,
) -> Result<Vec<String>, String> {
let res = generic_anki_connect_action("notesInfo", json!({ "notes": notes })).await;
let notes = Into::<Result<Vec<NoteInfo>, String>>::into(
res.json::<AnkiResult<Vec<NoteInfo>>>().await.unwrap(),
)?;

let mut words = Vec::new();

for note in notes {
if let Some(handler) = templates.get(&note.model_name) {
let selected_field = note
.fields
.into_iter()
.find(|x| x.0 == handler.field_to_use)
.unwrap()
.1
.value;
words.push(get_word_from_field(selected_field, handler))
} else {
return Err(format!(
"Unable to find model handler for {}",
note.model_name
));
) -> Result<Option<String>, String> {
if let Some(handler) = templates.get(&note.model_name) {
let res = generic_anki_connect_action("getNoteTags", json!({ "note": &note_id })).await;
let tags: Result<Vec<String>, String> =
res.json::<AnkiResult<Vec<String>>>().await.unwrap().into();

if !handler.tags_wanted.is_empty()
&& !tags?.iter().any(|t| handler.tags_wanted.contains(&t))
{
return Ok(None);
}

let selected_field = note
.fields
.into_iter()
.find(|x| x.0 == handler.field_to_use)
.unwrap()
.1
.value;
Ok(Some(get_word_from_field(selected_field, handler)))
} else {
Err(format!(
"Unable to find model handler for {}",
note.model_name
))
}
Ok(words)
}

fn get_word_from_field(selected_field: String, handler: &NoteToWordHandling) -> String {
let mut parsed = String::new();

let mut in_bracket = false;

for c in selected_field.chars() {
for c in selected_field.replace("&nbsp;", " ").chars() {
match c {
lp if lp == '[' || (lp == '(' && handler.remove_everything_in_parens) => {
if !in_bracket {
Expand All @@ -161,7 +174,7 @@ fn get_word_from_field(selected_field: String, handler: &NoteToWordHandling) ->
_ => (),
}
}
parsed
parsed.trim().to_owned()
}

#[tauri::command]
Expand Down
13 changes: 12 additions & 1 deletion src-ui/src/settings/wordknowledge_settings.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
use leptos::*;
use shared::NoteToWordHandling;

use crate::settings::{get_template_fields, shared_ui::SimpleDropDown};
use crate::settings::{
get_template_fields,
shared_ui::{SimpleDropDown, SimpleTextSetting},
};

type AnkiDeck = (
String,
Expand Down Expand Up @@ -74,6 +77,7 @@ fn IndividualDeckRepresentation(
field_to_use: String::new(),
only_first_word_or_line: false,
remove_everything_in_parens: false,
tags_wanted: Vec::new(),
};
wtempl.update(move |templs| templs.1.push(create_signal((String::new(), new_template))));
};
Expand Down Expand Up @@ -152,6 +156,13 @@ fn AnkiNoteParsing(
prop:value=move || rnote().1.remove_everything_in_parens
/>
</div>

<SimpleTextSetting
readsig=move || rnote().1.tags_wanted.join(" ")
writesig=move |inp| wnote.update(|v| v.1.tags_wanted = inp.split_whitespace().map(|t| t.to_string()).collect())
name="tags"
desc="Tags required"
/>
</div>
}
}

0 comments on commit abe0e2f

Please sign in to comment.