remade CardDisplay, added hints
This commit is contained in:
parent
38898e41c3
commit
8d4b92e247
|
@ -19,6 +19,11 @@
|
||||||
<property name="label">No card image found in database. If you think this is an error, please, create an issue.</property>
|
<property name="label">No card image found in database. If you think this is an error, please, create an issue.</property>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="incorrect_message">
|
||||||
|
<property name="visible">false</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkEntry" id="answer_entry">
|
<object class="GtkEntry" id="answer_entry">
|
||||||
<property name="halign">GTK_ALIGN_CENTER</property>
|
<property name="halign">GTK_ALIGN_CENTER</property>
|
||||||
|
|
|
@ -149,7 +149,7 @@ fn build_ui(app: &Application) {
|
||||||
closure_local!(
|
closure_local!(
|
||||||
@strong app, @strong memory_cards_game => move |_b: &Button| {
|
@strong app, @strong memory_cards_game => move |_b: &Button| {
|
||||||
switch_to(&app, AppWindow::MemoryCardsGameScene);
|
switch_to(&app, AppWindow::MemoryCardsGameScene);
|
||||||
memory_cards_game.update_card_list();
|
memory_cards_game.imp().update_card();
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use std::borrow::Borrow;
|
use std::borrow::Borrow;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
|
use std::fs;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
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;
|
||||||
|
@ -24,7 +24,7 @@ use gtk::{
|
||||||
};
|
};
|
||||||
use gtk::{prelude::*, FileDialog};
|
use gtk::{prelude::*, FileDialog};
|
||||||
use gtk::{ListItem, SignalListItemFactory};
|
use gtk::{ListItem, SignalListItemFactory};
|
||||||
use rusqlite::{Connection};
|
use rusqlite::Connection;
|
||||||
use sha256::try_digest;
|
use sha256::try_digest;
|
||||||
|
|
||||||
#[derive(CompositeTemplate, Default)]
|
#[derive(CompositeTemplate, Default)]
|
||||||
|
@ -62,21 +62,10 @@ impl ObjectSubclass for MemoryCardsEditScene {
|
||||||
impl ObjectImpl for MemoryCardsEditScene {
|
impl ObjectImpl for MemoryCardsEditScene {
|
||||||
fn constructed(&self) {
|
fn constructed(&self) {
|
||||||
self.parent_constructed();
|
self.parent_constructed();
|
||||||
// println!("test 1 outside");
|
|
||||||
// gio::spawn_blocking(|| {
|
|
||||||
// println!("test 1 inside");
|
|
||||||
// thread::sleep(Duration::from_secs(1));
|
|
||||||
// println!("test 2 inside");
|
|
||||||
// });
|
|
||||||
// println!("test 2 outside");
|
|
||||||
|
|
||||||
|
|
||||||
let binding = self.obj();
|
let binding = self.obj();
|
||||||
|
|
||||||
glib::spawn_future_local(clone!(@weak binding => async move {
|
glib::spawn_future_local(clone!(@weak binding => async move {
|
||||||
println!("Starting query");
|
|
||||||
binding.imp().query_cards(None);
|
binding.imp().query_cards(None);
|
||||||
println!("End query");
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
self.add_button.connect_closure("clicked",
|
self.add_button.connect_closure("clicked",
|
||||||
|
@ -95,21 +84,7 @@ impl ObjectImpl for MemoryCardsEditScene {
|
||||||
new_win.present();
|
new_win.present();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
let a = Connection::open_in_memory().expect("");
|
|
||||||
|
|
||||||
self.search_entry.connect_closure("activate", false, closure_local!(@strong binding => move |e: &SearchEntry| {
|
self.search_entry.connect_closure("activate", false, closure_local!(@strong binding => move |e: &SearchEntry| {
|
||||||
|
|
||||||
// Put query to the separate thread so that cards load on fly.
|
|
||||||
// gio::spawn_blocking(move || {
|
|
||||||
|
|
||||||
// });
|
|
||||||
|
|
||||||
// gio::spawn_blocking(move || {
|
|
||||||
// binding.imp().query_cards(None);
|
|
||||||
// });
|
|
||||||
// gio::spawn_blocking(clone!(@strong binding => move || {
|
|
||||||
// binding.imp().query_cards(None);
|
|
||||||
// }));
|
|
||||||
binding.imp().query_cards(
|
binding.imp().query_cards(
|
||||||
match e.text().as_str() {
|
match e.text().as_str() {
|
||||||
"" => None,
|
"" => None,
|
||||||
|
@ -242,60 +217,42 @@ impl MemoryCardsEditScene {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn query_cards(&self, options: Option<String>) {
|
pub fn query_cards(&self, options: Option<String>) {
|
||||||
let cards = self.displaying_cards.clone();
|
|
||||||
// let cl = move || {
|
|
||||||
|
|
||||||
|
|
||||||
// spawn(async move {p(&stmt, &self.displaying_cards).await});
|
|
||||||
p(options, &cards);
|
|
||||||
// let d = &self.displaying_cards;
|
|
||||||
// gio::spawn_blocking(|| p(options, d));
|
|
||||||
// gio::spawn_blocking(||t(options));
|
|
||||||
// spawn(move || block_on(
|
|
||||||
// p(options, &cards)
|
|
||||||
// ));
|
|
||||||
// gio::spawn_blocking(p(&stmt, &self.displaying_cards));
|
|
||||||
// cl();
|
|
||||||
// glib::MainContext::spawn_local(&self, cl);
|
|
||||||
// gio::spawn_blocking(cl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn p(options: Option<String>, cards: &Arc<Mutex<RefCell<Vec<CardEntry>>>>) {
|
let conn = Connection::open(get_db_path()).unwrap();
|
||||||
let conn = Connection::open(get_db_path()).unwrap();
|
|
||||||
|
|
||||||
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, is_learning FROM cards {selector}"
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut stmt = conn.prepare(sql.as_str()).unwrap();
|
|
||||||
|
|
||||||
// let mut stmt = stmt.lock().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),
|
let sql = format!(
|
||||||
Some(row.get(1).unwrap()),
|
"SELECT imagename, hieroglyph, reading, translation, is_learning FROM cards {selector}"
|
||||||
Some(row.get(2).unwrap()),
|
);
|
||||||
Some(row.get(3).unwrap()),
|
|
||||||
Some(row.get(4).unwrap()),
|
let mut stmt = conn.prepare(sql.as_str()).unwrap();
|
||||||
);
|
|
||||||
let entry = CardEntry::new(Some(&c));
|
// let mut stmt = stmt.lock().unwrap();
|
||||||
entry.update_state();
|
let cards_iter = stmt
|
||||||
Ok(entry)
|
.query_map([], |row| {
|
||||||
})
|
let image_path: String = match row.get(0) {
|
||||||
.unwrap();
|
Ok(path) => path,
|
||||||
for c in cards_iter {
|
Err(_) => String::from(""),
|
||||||
cards.lock().unwrap().borrow_mut().push(c.unwrap());
|
};
|
||||||
|
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()),
|
||||||
|
);
|
||||||
|
let entry = CardEntry::new(Some(&c));
|
||||||
|
entry.update_state();
|
||||||
|
Ok(entry)
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
for c in cards_iter {
|
||||||
|
self.displaying_cards.lock().unwrap().borrow_mut().push(c.unwrap());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
|
|
||||||
|
use crate::card::Card;
|
||||||
|
use crate::db::{get_db_path, get_images_store_path};
|
||||||
use crate::widgets::card_display::*;
|
use crate::widgets::card_display::*;
|
||||||
|
|
||||||
use glib::subclass::InitializingObject;
|
use glib::subclass::InitializingObject;
|
||||||
|
@ -7,6 +9,7 @@ use gtk::glib::clone;
|
||||||
use gtk::subclass::prelude::*;
|
use gtk::subclass::prelude::*;
|
||||||
use gtk::{glib, Box, Button, CompositeTemplate, Label};
|
use gtk::{glib, Box, Button, CompositeTemplate, Label};
|
||||||
use gtk::{prelude::*, Entry};
|
use gtk::{prelude::*, Entry};
|
||||||
|
use rusqlite::Connection;
|
||||||
|
|
||||||
#[derive(CompositeTemplate, Default)]
|
#[derive(CompositeTemplate, Default)]
|
||||||
#[template(resource = "/org/foxarmy/learn-hieroglyph/cards/game/ui.xml")]
|
#[template(resource = "/org/foxarmy/learn-hieroglyph/cards/game/ui.xml")]
|
||||||
|
@ -48,21 +51,75 @@ impl ObjectImpl for MemoryCardsGameScene {
|
||||||
let card_display_binding = self.card_display.imp().obj();
|
let card_display_binding = self.card_display.imp().obj();
|
||||||
let self_binding = self.obj();
|
let self_binding = self.obj();
|
||||||
|
|
||||||
self_binding.update_card_list();
|
self.update_card();
|
||||||
|
|
||||||
card_display_binding.get_answer_entry().connect_activate(clone!(@strong card_display_binding, @strong self_binding => move |e: &Entry| {
|
card_display_binding.get_answer_entry().connect_activate(clone!(@strong card_display_binding, @strong self_binding => move |e: &Entry| {
|
||||||
println!("{}", e.text());
|
card_display_binding.imp().incorrect_message.set_visible(false);
|
||||||
println!("{} = {}? -> {}", e.text(), card_display_binding.get_hieroglyph(), e.text().to_string() == *card_display_binding.get_hieroglyph());
|
let incorrect_message_label = &card_display_binding.imp().incorrect_message;
|
||||||
if e.text() == *card_display_binding.get_hieroglyph() {
|
if e.text() == *card_display_binding.hieroglyph() {
|
||||||
*self_binding.imp().correct.borrow_mut() += 1;
|
*self_binding.imp().correct.borrow_mut() += 1;
|
||||||
|
incorrect_message_label.set_visible(false);
|
||||||
} else {
|
} else {
|
||||||
*self_binding.imp().incorrect.borrow_mut() +=1;
|
*self_binding.imp().incorrect.borrow_mut() +=1;
|
||||||
|
incorrect_message_label.set_visible(true);
|
||||||
|
let message = format!("Incorrect! It was {} reading as {} with meaning {}", card_display_binding.hieroglyph(), card_display_binding.reading(), card_display_binding.translation());
|
||||||
|
incorrect_message_label.set_label(&message);
|
||||||
}
|
}
|
||||||
self_binding.update_stats();
|
self_binding.update_stats();
|
||||||
self_binding.update_card_list();
|
self_binding.imp().update_card();
|
||||||
e.set_text("");
|
e.set_text("");
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MemoryCardsGameScene {
|
||||||
|
pub fn update_card(&self) {
|
||||||
|
match generate_card() {
|
||||||
|
Some(card) => {
|
||||||
|
self.card_display.set_imagepath(card.imagepath());
|
||||||
|
self.card_display.set_hieroglyph(card.hieroglyph());
|
||||||
|
self.card_display.set_reading(card.reading());
|
||||||
|
self.card_display.set_translation(card.translation());
|
||||||
|
self.card_display.update_file_for_image();
|
||||||
|
},
|
||||||
|
None => { self.obj().show_no_cards_msg() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_card() -> Option<CardDisplay> {
|
||||||
|
let connection = Connection::open(get_db_path()).unwrap();
|
||||||
|
|
||||||
|
let mut stmt = connection.prepare("SELECT imagename, hieroglyph, reading, translation FROM cards WHERE is_learning = TRUE ORDER BY RANDOM() LIMIT 1").unwrap();
|
||||||
|
let random_card_iter = stmt
|
||||||
|
.query_map((), |row| {
|
||||||
|
Ok(Card::new(
|
||||||
|
row.get(0).unwrap(),
|
||||||
|
row.get(1).unwrap(),
|
||||||
|
row.get(2).unwrap(),
|
||||||
|
row.get(3).unwrap(),
|
||||||
|
None,
|
||||||
|
))
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let mut random_card = None;
|
||||||
|
for i in random_card_iter {
|
||||||
|
random_card = Some(i.unwrap());
|
||||||
|
}
|
||||||
|
let random_card: Card = match random_card {
|
||||||
|
Some(card) => card,
|
||||||
|
None => return None,
|
||||||
|
};
|
||||||
|
let generated_card = CardDisplay::new(
|
||||||
|
&(get_images_store_path() + "/" + &random_card.image_path().unwrap()),
|
||||||
|
&random_card.hieroglyph().unwrap(),
|
||||||
|
Some(&random_card.reading().unwrap()),
|
||||||
|
&random_card.translation().unwrap(),
|
||||||
|
);
|
||||||
|
Some(generated_card)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WidgetImpl for MemoryCardsGameScene {}
|
impl WidgetImpl for MemoryCardsGameScene {}
|
||||||
|
|
|
@ -2,7 +2,10 @@ mod imp;
|
||||||
|
|
||||||
use glib::Object;
|
use glib::Object;
|
||||||
use gtk::{
|
use gtk::{
|
||||||
gio, glib::{self, subclass::types::ObjectSubclassIsExt}, prelude::*, Application, Button
|
gio,
|
||||||
|
glib::{self, subclass::types::ObjectSubclassIsExt},
|
||||||
|
prelude::*,
|
||||||
|
Application, Button,
|
||||||
};
|
};
|
||||||
|
|
||||||
glib::wrapper! {
|
glib::wrapper! {
|
||||||
|
@ -17,10 +20,6 @@ impl MemoryCardsGameScene {
|
||||||
Object::builder().property("application", app).build()
|
Object::builder().property("application", app).build()
|
||||||
}
|
}
|
||||||
|
|
||||||
// pub fn set_stats(&self, correct: usize, incorrect: usize) {
|
|
||||||
// self.imp().stats_label.set_text(&format!("Correct|Incorrect: {correct}|{incorrect}"));
|
|
||||||
// }
|
|
||||||
|
|
||||||
pub fn update_stats(&self) {
|
pub fn update_stats(&self) {
|
||||||
self.imp().stats_label.set_text(&format!(
|
self.imp().stats_label.set_text(&format!(
|
||||||
"Correct|Incorrect: {}|{}",
|
"Correct|Incorrect: {}|{}",
|
||||||
|
@ -33,19 +32,9 @@ impl MemoryCardsGameScene {
|
||||||
self.imp().back_button.as_ref()
|
self.imp().back_button.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_card_list(&self) {
|
pub fn show_no_cards_msg(&self) {
|
||||||
match self.imp().card_display.generate_card() {
|
self.imp().card_display.set_visible(false);
|
||||||
Some(_) => {
|
self.imp().stats_label.set_visible(false);
|
||||||
self.imp().card_display.set_visible(true);
|
self.imp().no_cards_label.set_visible(true);
|
||||||
self.imp().stats_label.set_visible(true);
|
|
||||||
self.imp().no_cards_label.set_visible(false);
|
|
||||||
self.imp().card_display.generate_card();
|
|
||||||
},
|
|
||||||
None => {
|
|
||||||
self.imp().card_display.set_visible(false);
|
|
||||||
self.imp().stats_label.set_visible(false);
|
|
||||||
self.imp().no_cards_label.set_visible(true);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,10 +15,16 @@ pub struct CardDisplay {
|
||||||
pub answer_entry: TemplateChild<Entry>,
|
pub answer_entry: TemplateChild<Entry>,
|
||||||
#[template_child]
|
#[template_child]
|
||||||
pub error_message: TemplateChild<Label>,
|
pub error_message: TemplateChild<Label>,
|
||||||
|
#[template_child]
|
||||||
|
pub incorrect_message: TemplateChild<Label>,
|
||||||
#[property(get, set)]
|
#[property(get, set)]
|
||||||
pub imagepath: RefCell<String>,
|
pub imagepath: RefCell<String>,
|
||||||
#[property(get, set)]
|
#[property(get, set)]
|
||||||
pub hieroglyph: RefCell<String>,
|
pub hieroglyph: RefCell<String>,
|
||||||
|
#[property(get, set)]
|
||||||
|
pub reading: RefCell<String>,
|
||||||
|
#[property(get, set)]
|
||||||
|
pub translation: RefCell<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[glib::object_subclass]
|
#[glib::object_subclass]
|
||||||
|
|
|
@ -1,12 +1,9 @@
|
||||||
mod imp;
|
mod imp;
|
||||||
|
|
||||||
use std::cell::RefCell;
|
|
||||||
|
|
||||||
use glib::Object;
|
use glib::Object;
|
||||||
use gtk::{gio, glib::{self, subclass::types::ObjectSubclassIsExt}, prelude::*, Entry, Image};
|
use gtk::{gio, glib::{self, subclass::types::ObjectSubclassIsExt}, prelude::*, Entry, Image};
|
||||||
use rusqlite::Connection;
|
|
||||||
|
|
||||||
use crate::db::{get_db_path, get_images_store_path};
|
|
||||||
|
|
||||||
glib::wrapper! {
|
glib::wrapper! {
|
||||||
pub struct CardDisplay(ObjectSubclass<imp::CardDisplay>)
|
pub struct CardDisplay(ObjectSubclass<imp::CardDisplay>)
|
||||||
|
@ -15,17 +12,13 @@ glib::wrapper! {
|
||||||
gtk::ConstraintTarget, gtk::Native, gtk::Root, gtk::ShortcutManager;
|
gtk::ConstraintTarget, gtk::Native, gtk::Root, gtk::ShortcutManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Card {
|
|
||||||
imagename: String,
|
|
||||||
hieroglyph: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CardDisplay {
|
impl CardDisplay {
|
||||||
pub fn new(image_path: &String, hieroglyph: &String) -> Self {
|
pub fn new(image_path: &String, hieroglyph: &String, reading: Option<&String>, translation: &String) -> Self {
|
||||||
Object::builder()
|
Object::builder()
|
||||||
.property("imagepath", image_path)
|
.property("imagepath", image_path)
|
||||||
|
.property("translation", translation)
|
||||||
|
.property("reading", reading)
|
||||||
.property("hieroglyph", hieroglyph)
|
.property("hieroglyph", hieroglyph)
|
||||||
// .property("translation", translation)
|
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,48 +31,8 @@ impl CardDisplay {
|
||||||
}
|
}
|
||||||
image_binding.set_file(Some(&path));
|
image_binding.set_file(Some(&path));
|
||||||
}
|
}
|
||||||
pub fn generate_card(&self) -> Option<(&RefCell<String>, &RefCell<String>)> {
|
|
||||||
let connection = Connection::open(get_db_path()).unwrap();
|
|
||||||
|
|
||||||
let mut stmt = connection.prepare("SELECT imagename, hieroglyph FROM cards WHERE is_learning = TRUE ORDER BY RANDOM() LIMIT 1").unwrap();
|
|
||||||
let random_card_iter = stmt.query_map((), |row| {
|
|
||||||
Ok(
|
|
||||||
Card {
|
|
||||||
imagename: match row.get(0) {
|
|
||||||
Ok(value) => value,
|
|
||||||
Err(_) => String::from("")
|
|
||||||
},
|
|
||||||
hieroglyph: row.get(1).unwrap()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}).unwrap();
|
|
||||||
|
|
||||||
let mut random_card = None;
|
|
||||||
for i in random_card_iter {
|
|
||||||
random_card = Some(i.unwrap());
|
|
||||||
}
|
|
||||||
let random_card: Card = match random_card {
|
|
||||||
Some(card) => card,
|
|
||||||
None => return None
|
|
||||||
};
|
|
||||||
|
|
||||||
*self.imp().imagepath.borrow_mut() = get_images_store_path() + "/" + random_card.imagename.as_str();
|
|
||||||
*self.imp().hieroglyph.borrow_mut() = random_card.hieroglyph;
|
|
||||||
|
|
||||||
self.update_file_for_image();
|
|
||||||
|
|
||||||
connection.flush_prepared_statement_cache();
|
|
||||||
connection.cache_flush().expect("Cannot flush cache");
|
|
||||||
|
|
||||||
Some((&self.imp().imagepath, &self.imp().hieroglyph))
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_answer_entry(&self) -> &Entry {
|
pub fn get_answer_entry(&self) -> &Entry {
|
||||||
self.imp().answer_entry.as_ref()
|
self.imp().answer_entry.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_hieroglyph(&self) -> String {
|
|
||||||
self.imp().hieroglyph.borrow().clone()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue