Editing of cards

This commit is contained in:
leca 2024-04-16 23:21:48 +03:00
parent c2e6788a85
commit 0ad6550d0b
9 changed files with 139 additions and 31 deletions

View File

@ -3,7 +3,7 @@
<template class="MemoryCardsEditScene" parent="GtkApplicationWindow"> <template class="MemoryCardsEditScene" parent="GtkApplicationWindow">
<property name="title">Memory cards edit</property> <property name="title">Memory cards edit</property>
<property name="height-request">1000</property> <property name="height-request">1000</property>
<property name="width-request">500</property> <!-- <property name="width-request">500</property> -->
<child> <child>
<object class="GtkBox" id="content"> <object class="GtkBox" id="content">
<property name="orientation">vertical</property> <property name="orientation">vertical</property>

View File

@ -20,7 +20,7 @@
</child> </child>
<child> <child>
<object class="GtkLabel" id="translation_label"> <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="valign">GTK_ALIGN_CENTER</property>
<property name="margin-end">50</property> <property name="margin-end">50</property>
<property name="hexpand-set">true</property> <property name="hexpand-set">true</property>
@ -28,9 +28,18 @@
</object> </object>
</child> </child>
<child> <child>
<object class="GtkButton" id="delete_button"> <object class="GtkButton" id="edit_button">
<property name="halign">GTK_ALIGN_END</property> <property name="halign">GTK_ALIGN_END</property>
<property name="valign">GTK_ALIGN_CENTER</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="label">delete</property>
<property name="hexpand">true</property> <property name="hexpand">true</property>
<property name="hexpand-set">true</property> <property name="hexpand-set">true</property>

46
src/card/mod.rs Normal file
View 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,
}
}
}

View File

@ -11,6 +11,7 @@ mod game;
mod ui; mod ui;
mod widgets; mod widgets;
mod dictionary; mod dictionary;
mod card;
use crate::ui::menu::MenuScene; use crate::ui::menu::MenuScene;

View File

@ -1,21 +1,23 @@
use std::borrow::Borrow;
use std::cell::RefCell; use std::cell::RefCell;
use std::fs; use std::fs;
use std::io::ErrorKind; use std::io::ErrorKind;
use std::path::Path; use std::path::Path;
use std::rc::Rc; use std::rc::Rc;
use crate::card::*;
use crate::db::*; use crate::db::*;
use crate::ui::cards::new::*; use crate::ui::cards::new::*;
use crate::widgets::card_entry::CardEntry; use crate::widgets::card_entry::CardEntry;
use glib::subclass::InitializingObject; use glib::subclass::InitializingObject;
use gtk::glib::object::ObjectExt; use gtk::glib::object::ObjectExt;
use gtk::glib::{clone, closure_local}; use gtk::glib::{clone, closure_local};
use gtk::prelude::WidgetExt;
use gtk::subclass::prelude::*; use gtk::subclass::prelude::*;
use gtk::{gio, glib, Box, Button, CompositeTemplate, ScrolledWindow, SearchEntry, Window}; use gtk::{gio, glib, Box, Button, CompositeTemplate, ScrolledWindow, SearchEntry, Window};
use gtk::{prelude::*, FileDialog}; use gtk::{prelude::*, FileDialog};
use rusqlite::Connection; use rusqlite::Connection;
use sha256::try_digest; use sha256::try_digest;
use gtk::prelude::WidgetExt;
#[derive(CompositeTemplate, Default)] #[derive(CompositeTemplate, Default)]
#[template(resource = "/org/foxarmy/learn-hieroglyph/cards/edit/ui.xml")] #[template(resource = "/org/foxarmy/learn-hieroglyph/cards/edit/ui.xml")]
@ -31,7 +33,7 @@ pub struct MemoryCardsEditScene {
#[template_child] #[template_child]
pub back_button: TemplateChild<Button>, pub back_button: TemplateChild<Button>,
displaying_cards: RefCell<Vec<CardEntry>> displaying_cards: RefCell<Vec<CardEntry>>,
} }
#[glib::object_subclass] #[glib::object_subclass]
@ -64,14 +66,13 @@ impl ObjectImpl for MemoryCardsEditScene {
let new_win = Rc::new(MemoryCardsNewScene::new(&binding.application().unwrap())); 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| { new_win.get_file_choose_button().connect_clicked(clone!(@strong new_win => move |b: &Button| {
b.set_visible(false); 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| { new_win.get_done_button().connect_closure("clicked", true, closure_local!(@strong binding => move |_w: &Button| {
binding.imp().query_cards(None); binding.imp().query_cards(None);
binding.imp().update_card_list(); binding.imp().update_card_list();
})); }));
new_win.present(); new_win.present();
})); }));
self.search_entry.connect_closure("changed", false, closure_local!(@strong binding => move |e: &SearchEntry| { self.search_entry.connect_closure("changed", false, closure_local!(@strong binding => move |e: &SearchEntry| {
@ -80,7 +81,7 @@ impl ObjectImpl for MemoryCardsEditScene {
"" => None, "" => None,
_ => { _ => {
let search_option = e.text().to_string(); 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) Some(conditions)
} }
} }
@ -105,18 +106,17 @@ impl MemoryCardsEditScene {
let selector = match options { let selector = match options {
Some(s) => "WHERE ".to_owned() + &s, Some(s) => "WHERE ".to_owned() + &s,
None => "".to_owned() None => "".to_owned(),
}; };
let sql = format!("SELECT imagename, hieroglyph, reading, translation FROM cards {selector}"); let sql =
let mut stmt = conn format!("SELECT imagename, hieroglyph, reading, translation FROM cards {selector}");
.prepare(sql.as_str()) let mut stmt = conn.prepare(sql.as_str()).unwrap();
.unwrap();
let cards_iter = stmt let cards_iter = stmt
.query_map([], |row| { .query_map([], |row| {
let image_path: String = match row.get(0) { let image_path: String = match row.get(0) {
Ok(path) => path, Ok(path) => path,
Err(_) => String::from("") Err(_) => String::from(""),
}; };
let image_path: String = get_images_store_path() + &image_path; let image_path: String = get_images_store_path() + &image_path;
let hieroglyph: String = row.get(1).unwrap(); 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| { 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 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(); let imagename = &Path::new(&imagepath).file_name().unwrap().to_str().unwrap();
fs::remove_file(get_images_store_path() + "/" + &imagename).expect("Could not remove file!"); fs::remove_file(get_images_store_path() + "/" + &imagename).expect("Could not remove file!");
connection.execute("DELETE FROM cards WHERE imagename = ?1", [&imagename]).unwrap(); connection.execute("DELETE FROM cards WHERE imagename = ?1", [&imagename]).unwrap();
self_binding.imp().query_cards(None); self_binding.imp().query_cards(None);
self_binding.imp().update_card_list(); 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(); card.update_file_for_image();
} }
} }
} }
async fn file_choose_dialog<W: IsA<gtk::Window>>(window: Rc<W>) { async fn new_card_setup<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();
let w: &MemoryCardsNewScene = Into::<&Window>::into(window.upcast_ref()) let w: &MemoryCardsNewScene = Into::<&Window>::into(window.upcast_ref())
.downcast_ref() .downcast_ref()
.unwrap(); // Weird casting from &Window as passed in func to &MemoryCardsNewScene .unwrap(); // Weird casting from &Window as passed in func to &MemoryCardsNewScene
w.get_picture_widget() let picture_widget = w.get_picture_widget();
.set_file(Some(&gio::File::for_path(&path)));
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"; 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 translation = w.get_translation_input();
let conn = Connection::open(get_db_path()).unwrap(); 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(); conn.execute(query, (&new_filename, &hieroglyph, &reading, &translation)).unwrap();
println!("new imagepath: {new_filename}");
w.close(); w.close();
}), }),
); );

View File

@ -2,7 +2,7 @@ mod imp;
use glib::Object; use glib::Object;
use gtk::{ 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! { glib::wrapper! {
@ -29,6 +29,18 @@ impl MemoryCardsNewScene {
self.imp().heiroglyph_entry.text().to_string() 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 { pub fn get_reading_input(&self) -> String {
self.imp().reading_entry.text().to_string() self.imp().reading_entry.text().to_string()
} }

View File

@ -47,7 +47,7 @@ impl CardDisplay {
Card { Card {
imagename: match row.get(0) { imagename: match row.get(0) {
Ok(value) => value, Ok(value) => value,
Err(e) => String::from("") Err(_) => String::from("")
}, },
hieroglyph: row.get(1).unwrap() hieroglyph: row.get(1).unwrap()
} }

View File

@ -16,6 +16,8 @@ pub struct CardEntry {
#[template_child] #[template_child]
pub translation_label: TemplateChild<Label>, pub translation_label: TemplateChild<Label>,
#[template_child] #[template_child]
pub edit_button: TemplateChild<Button>,
#[template_child]
pub delete_button: TemplateChild<Button>, pub delete_button: TemplateChild<Button>,
#[property(get, set)] #[property(get, set)]
pub imagepath: RefCell<String>, pub imagepath: RefCell<String>,

View File

@ -31,6 +31,10 @@ impl CardEntry {
self.imp().delete_button.as_ref() 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) { pub fn update_file_for_image(&self) {
let image_binding: &Image = self.imp().image.as_ref(); let image_binding: &Image = self.imp().image.as_ref();
let path: &str = &*self.imp().imagepath.borrow().clone().to_string(); let path: &str = &*self.imp().imagepath.borrow().clone().to_string();