Editing of cards
This commit is contained in:
parent
c2e6788a85
commit
0ad6550d0b
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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 ui;
|
||||||
mod widgets;
|
mod widgets;
|
||||||
mod dictionary;
|
mod dictionary;
|
||||||
|
mod card;
|
||||||
|
|
||||||
use crate::ui::menu::MenuScene;
|
use crate::ui::menu::MenuScene;
|
||||||
|
|
||||||
|
|
|
@ -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| {
|
||||||
|
@ -79,8 +80,8 @@ impl ObjectImpl for MemoryCardsEditScene {
|
||||||
match e.text().as_str() {
|
match e.text().as_str() {
|
||||||
"" => 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();
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
|
@ -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()
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>,
|
||||||
|
|
|
@ -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();
|
||||||
|
|
Loading…
Reference in New Issue