Editing of cards
This commit is contained in:
		@@ -3,7 +3,7 @@
 | 
			
		||||
    <template class="MemoryCardsEditScene" parent="GtkApplicationWindow">
 | 
			
		||||
        <property name="title">Memory cards edit</property>
 | 
			
		||||
        <property name="height-request">1000</property>
 | 
			
		||||
        <property name="width-request">500</property>
 | 
			
		||||
        <!-- <property name="width-request">500</property> -->
 | 
			
		||||
        <child>
 | 
			
		||||
            <object class="GtkBox" id="content">
 | 
			
		||||
                <property name="orientation">vertical</property>
 | 
			
		||||
 
 | 
			
		||||
@@ -20,7 +20,7 @@
 | 
			
		||||
        </child>
 | 
			
		||||
        <child>
 | 
			
		||||
            <object class="GtkLabel" id="translation_label">
 | 
			
		||||
                <property name="halign">GTK_ALIGN_END</property>
 | 
			
		||||
                <property name="halign">GTK_ALIGN_START</property>
 | 
			
		||||
                <property name="valign">GTK_ALIGN_CENTER</property>
 | 
			
		||||
                <property name="margin-end">50</property>
 | 
			
		||||
                <property name="hexpand-set">true</property>
 | 
			
		||||
@@ -28,9 +28,18 @@
 | 
			
		||||
            </object>
 | 
			
		||||
        </child>
 | 
			
		||||
        <child>
 | 
			
		||||
            <object class="GtkButton" id="delete_button">
 | 
			
		||||
            <object class="GtkButton" id="edit_button">
 | 
			
		||||
                <property name="halign">GTK_ALIGN_END</property>
 | 
			
		||||
                <property name="valign">GTK_ALIGN_CENTER</property>
 | 
			
		||||
                <property name="label">edit</property>
 | 
			
		||||
                <property name="hexpand">true</property>
 | 
			
		||||
                <property name="hexpand-set">true</property>
 | 
			
		||||
            </object>
 | 
			
		||||
        </child>
 | 
			
		||||
        <child>
 | 
			
		||||
            <object class="GtkButton" id="delete_button">
 | 
			
		||||
                <property name="halign">GTK_ALIGN_START</property>
 | 
			
		||||
                <property name="valign">GTK_ALIGN_CENTER</property>
 | 
			
		||||
                <property name="label">delete</property>
 | 
			
		||||
                <property name="hexpand">true</property>
 | 
			
		||||
                <property name="hexpand-set">true</property>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										46
									
								
								src/card/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								src/card/mod.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,46 @@
 | 
			
		||||
use gtk::glib::Object;
 | 
			
		||||
 | 
			
		||||
pub struct Card {
 | 
			
		||||
    image_path: Option<String>,
 | 
			
		||||
    hieroglyph: Option<String>,
 | 
			
		||||
    reading: Option<String>,
 | 
			
		||||
    translation: Option<String>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Card {
 | 
			
		||||
 | 
			
		||||
    pub fn new(image_path: Option<String>, hieroglyph: Option<String>, reading: Option<String>, translation: Option<String>) -> Card {
 | 
			
		||||
        Card {
 | 
			
		||||
            image_path, hieroglyph, reading, translation
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn image_path(&self) -> Option<&String> {
 | 
			
		||||
        match &self.image_path {
 | 
			
		||||
            Some(v) => Some(&v),
 | 
			
		||||
            None => None,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn hieroglyp(&self) -> Option<&String> {
 | 
			
		||||
        match &self.image_path {
 | 
			
		||||
            Some(v) => Some(&v),
 | 
			
		||||
            None => None,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn reading(&self) -> Option<&String> {
 | 
			
		||||
        match &self.reading {
 | 
			
		||||
            Some(v) => Some(&v),
 | 
			
		||||
            None => None,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn translation(&self) -> Option<&String> {
 | 
			
		||||
        match &self.translation {
 | 
			
		||||
            Some(v) => Some(&v),
 | 
			
		||||
            None => None,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -11,6 +11,7 @@ mod game;
 | 
			
		||||
mod ui;
 | 
			
		||||
mod widgets;
 | 
			
		||||
mod dictionary;
 | 
			
		||||
mod card;
 | 
			
		||||
 | 
			
		||||
use crate::ui::menu::MenuScene;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,21 +1,23 @@
 | 
			
		||||
use std::borrow::Borrow;
 | 
			
		||||
use std::cell::RefCell;
 | 
			
		||||
use std::fs;
 | 
			
		||||
use std::io::ErrorKind;
 | 
			
		||||
use std::path::Path;
 | 
			
		||||
use std::rc::Rc;
 | 
			
		||||
 | 
			
		||||
use crate::card::*;
 | 
			
		||||
use crate::db::*;
 | 
			
		||||
use crate::ui::cards::new::*;
 | 
			
		||||
use crate::widgets::card_entry::CardEntry;
 | 
			
		||||
use glib::subclass::InitializingObject;
 | 
			
		||||
use gtk::glib::object::ObjectExt;
 | 
			
		||||
use gtk::glib::{clone, closure_local};
 | 
			
		||||
use gtk::prelude::WidgetExt;
 | 
			
		||||
use gtk::subclass::prelude::*;
 | 
			
		||||
use gtk::{gio, glib, Box, Button, CompositeTemplate, ScrolledWindow, SearchEntry, Window};
 | 
			
		||||
use gtk::{prelude::*, FileDialog};
 | 
			
		||||
use rusqlite::Connection;
 | 
			
		||||
use sha256::try_digest;
 | 
			
		||||
use gtk::prelude::WidgetExt;
 | 
			
		||||
 | 
			
		||||
#[derive(CompositeTemplate, Default)]
 | 
			
		||||
#[template(resource = "/org/foxarmy/learn-hieroglyph/cards/edit/ui.xml")]
 | 
			
		||||
@@ -31,7 +33,7 @@ pub struct MemoryCardsEditScene {
 | 
			
		||||
    #[template_child]
 | 
			
		||||
    pub back_button: TemplateChild<Button>,
 | 
			
		||||
 | 
			
		||||
    displaying_cards: RefCell<Vec<CardEntry>>
 | 
			
		||||
    displaying_cards: RefCell<Vec<CardEntry>>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[glib::object_subclass]
 | 
			
		||||
@@ -64,14 +66,13 @@ impl ObjectImpl for MemoryCardsEditScene {
 | 
			
		||||
                                        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(file_choose_dialog(Rc::clone(&new_win)));
 | 
			
		||||
                                            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);
 | 
			
		||||
                                            binding.imp().update_card_list();
 | 
			
		||||
                                        }));
 | 
			
		||||
                                        new_win.present();
 | 
			
		||||
                                        
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        self.search_entry.connect_closure("changed", false, closure_local!(@strong binding => move |e: &SearchEntry| {
 | 
			
		||||
@@ -80,7 +81,7 @@ impl ObjectImpl for MemoryCardsEditScene {
 | 
			
		||||
                    "" => None,
 | 
			
		||||
                    _ => {
 | 
			
		||||
                        let search_option = e.text().to_string();
 | 
			
		||||
                        let conditions = format!("hieroglyph LIKE '%{}%'", search_option);
 | 
			
		||||
                        let conditions = format!("hieroglyph LIKE '%{}%' OR reading LIKE '%{}%' OR translation LIKE '%{}%'", search_option, search_option, search_option);
 | 
			
		||||
                        Some(conditions)
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
@@ -105,18 +106,17 @@ impl MemoryCardsEditScene {
 | 
			
		||||
 | 
			
		||||
        let selector = match options {
 | 
			
		||||
            Some(s) => "WHERE ".to_owned() + &s,
 | 
			
		||||
            None => "".to_owned()
 | 
			
		||||
            None => "".to_owned(),
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        let sql = format!("SELECT imagename, hieroglyph, reading, translation FROM cards {selector}");
 | 
			
		||||
        let mut stmt = conn
 | 
			
		||||
            .prepare(sql.as_str())
 | 
			
		||||
            .unwrap();
 | 
			
		||||
        let sql =
 | 
			
		||||
            format!("SELECT imagename, hieroglyph, reading, translation 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){
 | 
			
		||||
                let image_path: String = match row.get(0) {
 | 
			
		||||
                    Ok(path) => path,
 | 
			
		||||
                    Err(_) => String::from("")
 | 
			
		||||
                    Err(_) => String::from(""),
 | 
			
		||||
                };
 | 
			
		||||
                let image_path: String = get_images_store_path() + &image_path;
 | 
			
		||||
                let hieroglyph: String = row.get(1).unwrap();
 | 
			
		||||
@@ -145,32 +145,65 @@ impl MemoryCardsEditScene {
 | 
			
		||||
 | 
			
		||||
            card.get_delete_button_widget().connect_closure("clicked", false, closure_local!(@strong card, @strong self_binding => move |_b: &Button| {
 | 
			
		||||
                let connection = Connection::open(get_db_path()).unwrap();
 | 
			
		||||
                let imagepath = card.imagepath();
 | 
			
		||||
                let imagepath = &card.imagepath();
 | 
			
		||||
                let imagename = &Path::new(&imagepath).file_name().unwrap().to_str().unwrap();
 | 
			
		||||
                fs::remove_file(get_images_store_path() + "/" + &imagename).expect("Could not remove file!");
 | 
			
		||||
                connection.execute("DELETE FROM cards WHERE imagename = ?1", [&imagename]).unwrap();
 | 
			
		||||
                self_binding.imp().query_cards(None);
 | 
			
		||||
                self_binding.imp().update_card_list();
 | 
			
		||||
            }));
 | 
			
		||||
 | 
			
		||||
            card.get_edit_button_widget().connect_closure("clicked", false, closure_local!(@strong self_binding as binding, @strong card => move |_b: &Button| {
 | 
			
		||||
                let new_win = Rc::new(MemoryCardsNewScene::new(&binding.application().unwrap()));
 | 
			
		||||
                //parsing hieroglyph and its reading from a card
 | 
			
		||||
                let hieroglyph_and_reading: String = card.hieroglyph();
 | 
			
		||||
 | 
			
		||||
                let reading_start = hieroglyph_and_reading.find("(").unwrap();
 | 
			
		||||
                let reading_end = hieroglyph_and_reading.find(")").unwrap();
 | 
			
		||||
 | 
			
		||||
                let hieroglyph = hieroglyph_and_reading[..reading_start-1].to_owned();
 | 
			
		||||
                let reading = hieroglyph_and_reading[reading_start..reading_end].to_owned();
 | 
			
		||||
                let translation = card.translation();
 | 
			
		||||
 | 
			
		||||
                //setting corresponding properties
 | 
			
		||||
                new_win.get_picture_widget().set_file(Some(&gio::File::for_path(card.imagepath())));
 | 
			
		||||
                new_win.get_hieroglyph_entry().set_text(&hieroglyph);
 | 
			
		||||
                new_win.get_reading_entry().set_text(&reading);
 | 
			
		||||
                new_win.get_translation_entry().set_text(&translation);
 | 
			
		||||
 | 
			
		||||
                new_win.get_file_choose_button().connect_clicked(clone!(@strong new_win, @strong card => 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);
 | 
			
		||||
                    binding.imp().update_card_list();
 | 
			
		||||
                }));
 | 
			
		||||
                new_win.present();
 | 
			
		||||
            }));
 | 
			
		||||
            card.update_file_for_image();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async fn file_choose_dialog<W: IsA<gtk::Window>>(window: Rc<W>) {
 | 
			
		||||
    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();
 | 
			
		||||
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
 | 
			
		||||
 | 
			
		||||
    w.get_picture_widget()
 | 
			
		||||
        .set_file(Some(&gio::File::for_path(&path)));
 | 
			
		||||
    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)));
 | 
			
		||||
 | 
			
		||||
    let images_store_path = get_program_home_path() + "/images";
 | 
			
		||||
 | 
			
		||||
@@ -196,8 +229,9 @@ async fn file_choose_dialog<W: IsA<gtk::Window>>(window: Rc<W>) {
 | 
			
		||||
            let translation = w.get_translation_input();
 | 
			
		||||
            let conn = Connection::open(get_db_path()).unwrap();
 | 
			
		||||
 | 
			
		||||
            let query = "INSERT INTO cards (imagename, hieroglyph, reading, translation) VALUES(?1, ?2, ?3, ?4)";
 | 
			
		||||
            let query = "INSERT OR REPLACE INTO cards (id, imagename, hieroglyph, reading, translation) VALUES((SELECT id FROM cards WHERE hieroglyph = ?2), ?1, ?2, ?3, ?4)";
 | 
			
		||||
            conn.execute(query, (&new_filename, &hieroglyph, &reading, &translation)).unwrap();
 | 
			
		||||
            println!("new imagepath: {new_filename}");
 | 
			
		||||
            w.close();
 | 
			
		||||
        }),
 | 
			
		||||
    );
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@ mod imp;
 | 
			
		||||
 | 
			
		||||
use glib::Object;
 | 
			
		||||
use gtk::{
 | 
			
		||||
    gio, glib::{self, subclass::types::ObjectSubclassIsExt}, prelude::*, Application, Button, Picture
 | 
			
		||||
    gio, glib::{self, subclass::types::ObjectSubclassIsExt}, prelude::*, Application, Button, Entry, Picture
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
glib::wrapper! {
 | 
			
		||||
@@ -29,6 +29,18 @@ impl MemoryCardsNewScene {
 | 
			
		||||
        self.imp().heiroglyph_entry.text().to_string()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn get_hieroglyph_entry(&self) -> &Entry {
 | 
			
		||||
        self.imp().heiroglyph_entry.as_ref()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn get_reading_entry(&self) -> &Entry {
 | 
			
		||||
        self.imp().reading_entry.as_ref()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn get_translation_entry(&self) -> &Entry {
 | 
			
		||||
        self.imp().translation_entry.as_ref()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn get_reading_input(&self) -> String {
 | 
			
		||||
        self.imp().reading_entry.text().to_string()
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -47,7 +47,7 @@ impl CardDisplay {
 | 
			
		||||
                Card {
 | 
			
		||||
                    imagename: match row.get(0) {
 | 
			
		||||
                        Ok(value) => value,
 | 
			
		||||
                        Err(e) => String::from("")
 | 
			
		||||
                        Err(_) => String::from("")
 | 
			
		||||
                    },
 | 
			
		||||
                    hieroglyph: row.get(1).unwrap()
 | 
			
		||||
                }
 | 
			
		||||
 
 | 
			
		||||
@@ -16,6 +16,8 @@ pub struct CardEntry {
 | 
			
		||||
    #[template_child]
 | 
			
		||||
    pub translation_label: TemplateChild<Label>,
 | 
			
		||||
    #[template_child]
 | 
			
		||||
    pub edit_button: TemplateChild<Button>,
 | 
			
		||||
    #[template_child]
 | 
			
		||||
    pub delete_button: TemplateChild<Button>,
 | 
			
		||||
    #[property(get, set)]
 | 
			
		||||
    pub imagepath: RefCell<String>,
 | 
			
		||||
 
 | 
			
		||||
@@ -31,6 +31,10 @@ impl CardEntry {
 | 
			
		||||
        self.imp().delete_button.as_ref()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn get_edit_button_widget(&self) -> &Button {
 | 
			
		||||
        self.imp().edit_button.as_ref()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn update_file_for_image(&self) {
 | 
			
		||||
        let image_binding: &Image = self.imp().image.as_ref();
 | 
			
		||||
        let path: &str = &*self.imp().imagepath.borrow().clone().to_string();
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user