ankiconnect_rs/builders/
note.rs

1//! Builder for creating notes with a fluent interface
2
3use crate::error::NoteError;
4use crate::models::{FieldMedia, FieldRef, Media, MediaSource, Model, Note};
5use std::collections::{HashMap, HashSet};
6
7/// Builder for creating Anki notes
8pub struct NoteBuilder {
9    model: Model,
10    field_values: HashMap<String, String>,
11    tags: HashSet<String>,
12    media: Vec<FieldMedia>,
13}
14
15impl NoteBuilder {
16    /// Creates a new NoteBuilder for the given model
17    pub fn new(model: Model) -> Self {
18        Self {
19            model,
20            field_values: HashMap::new(),
21            tags: HashSet::new(),
22            media: Vec::new(),
23        }
24    }
25
26    /// Add a field value with HTML escaping
27    pub fn with_field(mut self, field_ref: FieldRef<'_>, content: &str) -> Self {
28        let escaped_content = html_escape::encode_text(content).to_string();
29        self.field_values
30            .insert(field_ref.name().to_string(), escaped_content);
31        self
32    }
33
34    /// Add a field value without HTML escaping
35    pub fn with_field_raw(mut self, field_ref: FieldRef<'_>, content: &str) -> Self {
36        self.field_values
37            .insert(field_ref.name().to_string(), content.to_string());
38        self
39    }
40
41    /// Add a tag
42    pub fn with_tag(mut self, tag: &str) -> Self {
43        self.tags.insert(tag.to_string());
44        self
45    }
46
47    /// Add audio to a specific field
48    pub fn with_audio(self, field_ref: FieldRef<'_>, source: MediaSource, filename: &str) -> Self {
49        self.with_media(field_ref, Media::audio(source, filename.to_string()))
50    }
51
52    /// Add image to a specific field
53    pub fn with_image(self, field_ref: FieldRef<'_>, source: MediaSource, filename: &str) -> Self {
54        self.with_media(field_ref, Media::image(source, filename.to_string()))
55    }
56
57    /// Add video to a specific field
58    pub fn with_video(self, field_ref: FieldRef<'_>, source: MediaSource, filename: &str) -> Self {
59        self.with_media(field_ref, Media::video(source, filename.to_string()))
60    }
61
62    /// Add generic media to a specific field
63    pub fn with_media(mut self, field_ref: FieldRef<'_>, media: Media) -> Self {
64        self.media.push(FieldMedia {
65            media,
66            field: field_ref.name().to_string(),
67        });
68        self
69    }
70
71    /// Build the note, validating all required fields are present
72    pub fn build(self) -> Result<Note, NoteError> {
73        Note::new(self.model, self.field_values, self.tags, self.media)
74    }
75}