260 lines
9.6 KiB
Rust
260 lines
9.6 KiB
Rust
use std::cell::RefCell;
|
|
use std::fs;
|
|
use std::io::ErrorKind;
|
|
use std::path::Path;
|
|
use std::rc::Rc;
|
|
|
|
use crate::card::Card;
|
|
use crate::db::*;
|
|
use crate::ui::cards::new::*;
|
|
use crate::widgets::card_entry::CardEntry;
|
|
use glib::subclass::InitializingObject;
|
|
use gtk::gio::ListStore;
|
|
// use gtk::glib::ffi::GString;
|
|
use gtk::glib::object::ObjectExt;
|
|
use gtk::glib::GString;
|
|
use gtk::glib::{clone, closure_local};
|
|
use gtk::prelude::WidgetExt;
|
|
use gtk::subclass::prelude::*;
|
|
use gtk::{
|
|
gio, glib, Button, CompositeTemplate, ListView, NoSelection, ScrolledWindow, SearchEntry,
|
|
Window,
|
|
};
|
|
use gtk::{prelude::*, FileDialog};
|
|
use gtk::{ListBox, ListItem, SignalListItemFactory};
|
|
use rusqlite::Connection;
|
|
use sha256::try_digest;
|
|
|
|
#[derive(CompositeTemplate, Default)]
|
|
#[template(resource = "/org/foxarmy/learn-hieroglyph/cards/edit/ui.xml")]
|
|
pub struct MemoryCardsEditScene {
|
|
#[template_child]
|
|
pub search_entry: TemplateChild<SearchEntry>,
|
|
#[template_child]
|
|
pub add_button: TemplateChild<Button>,
|
|
#[template_child]
|
|
pub cards_container: TemplateChild<ListView>,
|
|
#[template_child]
|
|
pub cards_scrolled_window: TemplateChild<ScrolledWindow>,
|
|
#[template_child]
|
|
pub back_button: TemplateChild<Button>,
|
|
|
|
displaying_cards: RefCell<Vec<CardEntry>>,
|
|
}
|
|
|
|
#[glib::object_subclass]
|
|
impl ObjectSubclass for MemoryCardsEditScene {
|
|
const NAME: &'static str = "MemoryCardsEditScene";
|
|
type Type = super::MemoryCardsEditScene;
|
|
type ParentType = gtk::ApplicationWindow;
|
|
|
|
fn class_init(klass: &mut Self::Class) {
|
|
klass.bind_template();
|
|
}
|
|
|
|
fn instance_init(obj: &InitializingObject<Self>) {
|
|
obj.init_template();
|
|
}
|
|
}
|
|
|
|
impl ObjectImpl for MemoryCardsEditScene {
|
|
fn constructed(&self) {
|
|
self.parent_constructed();
|
|
|
|
let binding = self.obj();
|
|
|
|
self.add_button.connect_closure("clicked",
|
|
false,
|
|
closure_local!(@strong binding => move |_b: &Button| {
|
|
let new_win = Rc::new(MemoryCardsNewScene::new(&binding.application().unwrap()));
|
|
new_win.get_file_choose_button().connect_clicked(clone!(@strong new_win => move |b: &Button| {
|
|
b.set_visible(false);
|
|
gtk::glib::MainContext::default().spawn_local(new_card_setup(Rc::clone(&new_win)));
|
|
}));
|
|
new_win.get_done_button().connect_closure("clicked", true, closure_local!(@strong binding => move |_w: &Button| {
|
|
binding.imp().query_cards(None);
|
|
}));
|
|
new_win.present();
|
|
}));
|
|
|
|
self.search_entry.connect_closure("activate", false, closure_local!(@strong binding => move |e: &SearchEntry| {
|
|
binding.imp().query_cards(
|
|
match e.text().as_str() {
|
|
"" => None,
|
|
_ => {
|
|
let search_option = e.text().to_string();
|
|
let conditions = format!("hieroglyph LIKE '%{}%' OR reading LIKE '%{}%' OR translation LIKE '%{}%'", search_option, search_option, search_option);
|
|
Some(conditions)
|
|
}
|
|
}
|
|
);
|
|
}));
|
|
self.query_cards(None);
|
|
}
|
|
}
|
|
|
|
impl MemoryCardsEditScene {
|
|
pub fn query_cards(&self, options: Option<String>) {
|
|
let conn = Connection::open(get_db_path()).unwrap();
|
|
|
|
let selector = match options {
|
|
Some(s) => "WHERE ".to_owned() + &s,
|
|
None => "".to_owned(),
|
|
};
|
|
|
|
let sql = format!(
|
|
"SELECT imagename, hieroglyph, reading, translation, is_learning FROM cards {selector}"
|
|
);
|
|
let mut stmt = conn.prepare(sql.as_str()).unwrap();
|
|
let cards_iter = stmt
|
|
.query_map([], |row| {
|
|
let image_path: String = match row.get(0) {
|
|
Ok(path) => path,
|
|
Err(_) => String::from(""),
|
|
};
|
|
let c = Card::new(
|
|
Some(get_images_store_path() + &image_path),
|
|
Some(row.get(1).unwrap()),
|
|
Some(row.get(2).unwrap()),
|
|
Some(row.get(3).unwrap()),
|
|
Some(row.get(4).unwrap()),
|
|
);
|
|
// println!("{c:?} ");
|
|
|
|
let entry = CardEntry::new(Some(&c));
|
|
entry.update_state();
|
|
Ok(entry)
|
|
})
|
|
.unwrap();
|
|
self.displaying_cards.borrow_mut().clear();
|
|
println!("pos1");
|
|
for c in cards_iter {
|
|
self.displaying_cards.borrow_mut().push(c.unwrap());
|
|
}
|
|
println!("pos2");
|
|
|
|
let model = ListStore::new::<CardEntry>();
|
|
model.extend_from_slice(&*self.displaying_cards.borrow());
|
|
|
|
let factory = SignalListItemFactory::new();
|
|
factory.connect_setup(move |_, list_item| {
|
|
let card_entry = CardEntry::new(None);
|
|
list_item
|
|
.downcast_ref::<ListItem>()
|
|
.unwrap()
|
|
.set_child(Some(&card_entry));
|
|
});
|
|
|
|
factory.connect_bind(move |_, list_item| {
|
|
let card_object = &list_item
|
|
.downcast_ref::<ListItem>()
|
|
.unwrap()
|
|
.item()
|
|
.and_downcast::<CardEntry>()
|
|
.unwrap();
|
|
|
|
let card_object_to_display = list_item
|
|
.downcast_ref::<ListItem>()
|
|
.unwrap()
|
|
.child()
|
|
.and_downcast::<CardEntry>()
|
|
.unwrap();
|
|
|
|
// let path =
|
|
// // card_object_to_display.get_image_widget().set_file(Some(
|
|
// // // &card_object.get_image_widget().file().unwrap()
|
|
// // match card_object.get_image_widget().file() {
|
|
// // None => "",
|
|
// // Some(t) => {
|
|
// // t.to_string().to_owned().as_str()
|
|
// // }
|
|
// // }
|
|
// // ));
|
|
card_object_to_display.get_image_widget().set_file(Some(card_object.get_image_file_path().as_str()));
|
|
card_object_to_display.set_hieroglyph(card_object.hieroglyph());
|
|
card_object_to_display.set_reading(card_object.reading());
|
|
card_object_to_display.set_translation(card_object.translation());
|
|
card_object_to_display.set_islearning(card_object.islearning());
|
|
});
|
|
|
|
println!("pos3");
|
|
|
|
let no_selection_model = NoSelection::new(Some(model));
|
|
let list_view = ListView::new(Some(no_selection_model), Some(factory));
|
|
self.cards_scrolled_window.set_child(Some(&list_view));
|
|
println!("pos4");
|
|
}
|
|
}
|
|
|
|
async fn new_card_setup<W: IsA<gtk::Window>>(window: Rc<W>) {
|
|
let w: &MemoryCardsNewScene = Into::<&Window>::into(window.upcast_ref())
|
|
.downcast_ref()
|
|
.unwrap(); // Weird casting from &Window as passed in func to &MemoryCardsNewScene
|
|
|
|
let picture_widget = w.get_picture_widget();
|
|
|
|
let dialog: FileDialog = gtk::FileDialog::builder().build();
|
|
let answer = dialog.open_future(Some(&*window)).await;
|
|
let path = match answer {
|
|
Ok(p) => p,
|
|
Err(_) => return,
|
|
}
|
|
.path()
|
|
.unwrap();
|
|
let path: String = path.as_path().to_str().unwrap().to_owned();
|
|
|
|
picture_widget.set_file(Some(&gio::File::for_path(&path)));
|
|
println!("Image path has changed");
|
|
|
|
let images_store_path = get_program_home_path() + "/images";
|
|
|
|
match fs::create_dir_all(&images_store_path) {
|
|
Ok(_) => {}
|
|
Err(error) => match error.kind() {
|
|
ErrorKind::AlreadyExists => {}
|
|
_ => panic!("Could not create directory for storing images!"),
|
|
},
|
|
};
|
|
w.get_done_button().connect_closure(
|
|
"clicked",
|
|
false,
|
|
closure_local!(@strong w, @strong path => move |_b: &Button| {
|
|
let hash = try_digest(&path).unwrap();
|
|
let extenstion = Path::new(path.as_str()).extension().unwrap().to_str().unwrap();
|
|
let new_filename: String = hash.as_str().to_owned() + "." + extenstion;
|
|
let stored_image_path = Path::new(&images_store_path).join(&new_filename);
|
|
fs::copy(&path, stored_image_path).expect("Error copying image to store");
|
|
|
|
let hieroglyph = w.get_hieroglyph_input();
|
|
let reading = w.get_reading_input();
|
|
let translation = w.get_translation_input();
|
|
let conn = Connection::open(get_db_path()).unwrap();
|
|
|
|
conn.execute("INSERT OR REPLACE INTO cards ( id,
|
|
imagename,
|
|
hieroglyph,
|
|
reading,
|
|
translation,
|
|
is_learning
|
|
) VALUES (
|
|
(SELECT id FROM cards WHERE hieroglyph = ?2),
|
|
?1,
|
|
?2,
|
|
?3,
|
|
?4,
|
|
(SELECT is_learning FROM cards WHERE hieroglyph = ?2
|
|
)
|
|
)", (&new_filename, &hieroglyph, &reading, &translation)).unwrap();
|
|
conn.execute("UPDATE cards SET is_learning = TRUE WHERE hieroglyph = ?1", [&hieroglyph]).unwrap();
|
|
w.close();
|
|
|
|
}),
|
|
);
|
|
}
|
|
|
|
impl WidgetImpl for MemoryCardsEditScene {}
|
|
|
|
impl WindowImpl for MemoryCardsEditScene {}
|
|
|
|
impl ApplicationWindowImpl for MemoryCardsEditScene {}
|