Make db creation better
This commit is contained in:
@@ -0,0 +1,9 @@
|
|||||||
|
create table card_set
|
||||||
|
(
|
||||||
|
id INTEGER
|
||||||
|
primary key autoincrement,
|
||||||
|
name TEXT not null,
|
||||||
|
forward TEXT not null,
|
||||||
|
backward TEXT not null,
|
||||||
|
filter TEXT not null
|
||||||
|
);
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
create table card_stats
|
||||||
|
(
|
||||||
|
id INTEGER
|
||||||
|
primary key autoincrement,
|
||||||
|
word_id INTEGER not null
|
||||||
|
references words
|
||||||
|
on delete cascade,
|
||||||
|
set_id TEXT not null
|
||||||
|
references card_set
|
||||||
|
on delete cascade,
|
||||||
|
score INTEGER default 1 not null,
|
||||||
|
last_opened integer not null
|
||||||
|
);
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
create table settings
|
||||||
|
(
|
||||||
|
id text primary key,
|
||||||
|
value text
|
||||||
|
);
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
create table word_group
|
||||||
|
(
|
||||||
|
id INTEGER
|
||||||
|
primary key autoincrement,
|
||||||
|
name TEXT not null
|
||||||
|
);
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
create table words
|
||||||
|
(
|
||||||
|
id INTEGER
|
||||||
|
primary key autoincrement,
|
||||||
|
key TEXT not null,
|
||||||
|
value TEXT not null,
|
||||||
|
tags TEXT not null,
|
||||||
|
more TEXT,
|
||||||
|
group_id integer default 1 not null
|
||||||
|
constraint words_word_group_id_fk
|
||||||
|
references word_group
|
||||||
|
on update cascade on delete cascade
|
||||||
|
);
|
||||||
@@ -3,4 +3,5 @@ pub(crate) mod card_sets;
|
|||||||
pub(crate) mod card_stats;
|
pub(crate) mod card_stats;
|
||||||
pub(crate) mod voice;
|
pub(crate) mod voice;
|
||||||
pub(crate) mod settings;
|
pub(crate) mod settings;
|
||||||
|
pub(crate) mod sqlite;
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
use rusqlite::fallible_iterator::FallibleIterator;
|
|
||||||
use rusqlite::Connection;
|
use rusqlite::Connection;
|
||||||
|
|
||||||
pub fn get_setting(key: String, connection: &Connection) -> Option<String> {
|
pub fn get_setting(key: String, connection: &Connection) -> Option<String> {
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
use crate::dictionary::app_data_dir;
|
||||||
|
use rusqlite::Connection;
|
||||||
|
|
||||||
|
pub fn create_db() {
|
||||||
|
let path = app_data_dir();
|
||||||
|
let db_file = path.join("data.db");
|
||||||
|
if !db_file.exists() {
|
||||||
|
std::fs::File::create(&db_file).unwrap();
|
||||||
|
let connection = Connection::open(&db_file).unwrap();
|
||||||
|
connection.execute("PRAGMA foreign_keys = ON;", []).unwrap();
|
||||||
|
|
||||||
|
create_tables(&connection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_tables(conn: &Connection) {
|
||||||
|
make_card_set(conn).unwrap();
|
||||||
|
make_settings(conn).unwrap();
|
||||||
|
make_word_group(conn).unwrap();
|
||||||
|
make_words(conn).unwrap();
|
||||||
|
make_card_stats(conn).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_settings(conn: &Connection) -> Result<(), rusqlite::Error> {
|
||||||
|
let query = include_str!("../../sql/settings.sql");
|
||||||
|
conn.execute(query, ())?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_card_set(conn: &Connection) -> Result<(), rusqlite::Error> {
|
||||||
|
let query = include_str!("../../sql/card_set.sql");
|
||||||
|
conn.execute(query, ())?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_word_group(conn: &Connection) -> Result<(), rusqlite::Error> {
|
||||||
|
let query = include_str!("../../sql/word_group.sql");
|
||||||
|
conn.execute(query, ())?;
|
||||||
|
conn.execute("insert into word_group (name) values (\"Слова\");", ())?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
fn make_words(conn: &Connection) -> Result<(), rusqlite::Error> {
|
||||||
|
let query = include_str!("../../sql/words.sql");
|
||||||
|
conn.execute(query, ())?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
fn make_card_stats(conn: &Connection) -> Result<(), rusqlite::Error> {
|
||||||
|
let query = include_str!("../../sql/card_stats.sql");
|
||||||
|
conn.execute(query, ())?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
@@ -1,95 +1,7 @@
|
|||||||
use crate::dictionary::app_data_dir;
|
|
||||||
use crate::lang::{WordData, WordGroup};
|
use crate::lang::{WordData, WordGroup};
|
||||||
use rusqlite::Connection;
|
use rusqlite::Connection;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
pub fn create_db() {
|
|
||||||
let path = app_data_dir();
|
|
||||||
let db_file = path.join("data.db");
|
|
||||||
if !db_file.exists() {
|
|
||||||
std::fs::File::create(&db_file).unwrap();
|
|
||||||
let connection = Connection::open(&db_file).unwrap();
|
|
||||||
connection.execute("PRAGMA foreign_keys = ON;", []).unwrap();
|
|
||||||
|
|
||||||
create_tables(&connection);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_tables(conn: &Connection) {
|
|
||||||
conn.execute(
|
|
||||||
"create table settings
|
|
||||||
(
|
|
||||||
id text primary key,
|
|
||||||
value text
|
|
||||||
);",
|
|
||||||
(),
|
|
||||||
)
|
|
||||||
.unwrap_or_else(|e| 0);
|
|
||||||
|
|
||||||
conn.execute(
|
|
||||||
"create table card_set
|
|
||||||
(
|
|
||||||
id INTEGER
|
|
||||||
primary key autoincrement,
|
|
||||||
name TEXT not null,
|
|
||||||
forward TEXT not null,
|
|
||||||
backward TEXT not null,
|
|
||||||
filter TEXT not null
|
|
||||||
);",
|
|
||||||
(),
|
|
||||||
)
|
|
||||||
.unwrap_or_else(|e| 0);
|
|
||||||
conn.execute(
|
|
||||||
"create table word_group
|
|
||||||
(
|
|
||||||
id INTEGER
|
|
||||||
primary key autoincrement,
|
|
||||||
name TEXT not null
|
|
||||||
);",
|
|
||||||
(),
|
|
||||||
)
|
|
||||||
.unwrap_or_else(|e| 0);
|
|
||||||
conn.execute(
|
|
||||||
"create table words
|
|
||||||
(
|
|
||||||
id INTEGER
|
|
||||||
primary key autoincrement,
|
|
||||||
key TEXT not null,
|
|
||||||
value TEXT not null,
|
|
||||||
tags TEXT not null,
|
|
||||||
more TEXT,
|
|
||||||
group_id integer default 1 not null
|
|
||||||
constraint words_word_group_id_fk
|
|
||||||
references word_group
|
|
||||||
on update cascade on delete cascade
|
|
||||||
);",
|
|
||||||
(),
|
|
||||||
)
|
|
||||||
.unwrap_or_else(|e| 0);
|
|
||||||
conn.execute(
|
|
||||||
"create table card_stats
|
|
||||||
(
|
|
||||||
id INTEGER
|
|
||||||
primary key autoincrement,
|
|
||||||
word_id INTEGER not null
|
|
||||||
references words
|
|
||||||
on delete cascade,
|
|
||||||
set_id TEXT not null
|
|
||||||
references card_set
|
|
||||||
on delete cascade,
|
|
||||||
score INTEGER default 1 not null,
|
|
||||||
last_opened integer not null
|
|
||||||
);",
|
|
||||||
(),
|
|
||||||
)
|
|
||||||
.unwrap_or_else(|e| 0);
|
|
||||||
conn.execute(
|
|
||||||
"insert into word_group (name)
|
|
||||||
values (\"Слова\");",
|
|
||||||
(),
|
|
||||||
)
|
|
||||||
.unwrap_or_else(|e| 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_word(word: &mut WordData, connection: &Connection) {
|
pub fn add_word(word: &mut WordData, connection: &Connection) {
|
||||||
let index = connection
|
let index = connection
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ use iced::widget::space::horizontal;
|
|||||||
use iced::widget::*;
|
use iced::widget::*;
|
||||||
use iced::{Border, Color, Length, Shadow, Task};
|
use iced::{Border, Color, Length, Shadow, Task};
|
||||||
use rand::random_range;
|
use rand::random_range;
|
||||||
use rayon::iter::IndexedParallelIterator;
|
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::ops::Add;
|
use std::ops::Add;
|
||||||
@@ -35,7 +34,6 @@ pub struct DictionaryState {
|
|||||||
selected_group_index: usize,
|
selected_group_index: usize,
|
||||||
reverse_list: bool,
|
reverse_list: bool,
|
||||||
auto_save_queue: HashMap<usize, DateTime<Utc>>,
|
auto_save_queue: HashMap<usize, DateTime<Utc>>,
|
||||||
total_tags_list: Vec<String>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@@ -117,7 +115,6 @@ impl DictionaryState {
|
|||||||
no_typing: true,
|
no_typing: true,
|
||||||
reverse_list: true,
|
reverse_list: true,
|
||||||
auto_save_queue: HashMap::new(),
|
auto_save_queue: HashMap::new(),
|
||||||
total_tags_list: vec![],
|
|
||||||
};
|
};
|
||||||
|
|
||||||
result.update_tags();
|
result.update_tags();
|
||||||
|
|||||||
+62
-62
@@ -277,10 +277,10 @@ impl CardStatistics {
|
|||||||
}
|
}
|
||||||
WordOpenMode::Ok => self.score = (self.calculated_score() + 2.0).round() as i32,
|
WordOpenMode::Ok => self.score = (self.calculated_score() + 2.0).round() as i32,
|
||||||
WordOpenMode::Hard => {
|
WordOpenMode::Hard => {
|
||||||
self.score = (self.calculated_score() - 1.0).round() as i32;
|
self.score = (self.calculated_score() * 0.75).round() as i32;
|
||||||
}
|
}
|
||||||
WordOpenMode::None => {
|
WordOpenMode::None => {
|
||||||
self.score = (self.calculated_score() * 0.5) as i32;
|
self.score = (self.calculated_score() * 0.4) as i32;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -359,9 +359,9 @@ impl CardSet {
|
|||||||
state: state_for,
|
state: state_for,
|
||||||
order_module: match settings.open_mode {
|
order_module: match settings.open_mode {
|
||||||
SetOrderMode::Default => OrderModule::SemiRandomSRS(SemiRandomSRSModule::new()),
|
SetOrderMode::Default => OrderModule::SemiRandomSRS(SemiRandomSRSModule::new()),
|
||||||
SetOrderMode::TrainWorstFirst => {
|
// SetOrderMode::TrainWorstFirst => {
|
||||||
OrderModule::WorstWordsSRS(WorstWordsSRSModule::new())
|
// OrderModule::WorstWordsSRS(WorstWordsSRSModule::new())
|
||||||
}
|
// }
|
||||||
SetOrderMode::FullRandom => OrderModule::RandomSRS(RandomSRSModule::new()),
|
SetOrderMode::FullRandom => OrderModule::RandomSRS(RandomSRSModule::new()),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -370,7 +370,7 @@ impl CardSet {
|
|||||||
pub fn next(&mut self) -> (WordData, CardStatistics) {
|
pub fn next(&mut self) -> (WordData, CardStatistics) {
|
||||||
let index = match self.order_module.clone() {
|
let index = match self.order_module.clone() {
|
||||||
OrderModule::SemiRandomSRS(mut module) => {
|
OrderModule::SemiRandomSRS(mut module) => {
|
||||||
if module.initializated == false {
|
if module.initialized == false {
|
||||||
module.init(self)
|
module.init(self)
|
||||||
}
|
}
|
||||||
let index = module.next(self);
|
let index = module.next(self);
|
||||||
@@ -378,21 +378,21 @@ impl CardSet {
|
|||||||
index
|
index
|
||||||
}
|
}
|
||||||
OrderModule::RandomSRS(mut module) => {
|
OrderModule::RandomSRS(mut module) => {
|
||||||
if module.initializated == false {
|
if module.initialized == false {
|
||||||
module.init(self)
|
module.init(self)
|
||||||
}
|
}
|
||||||
let index = module.next(self);
|
let index = module.next(self);
|
||||||
self.order_module = OrderModule::RandomSRS(module);
|
self.order_module = OrderModule::RandomSRS(module);
|
||||||
index
|
index
|
||||||
}
|
}
|
||||||
OrderModule::WorstWordsSRS(mut module) => {
|
// OrderModule::WorstWordsSRS(mut module) => {
|
||||||
if module.initializated == false {
|
// if module.initializated == false {
|
||||||
module.init(self)
|
// module.init(self)
|
||||||
}
|
// }
|
||||||
let index = module.next(self);
|
// let index = module.next(self);
|
||||||
self.order_module = OrderModule::WorstWordsSRS(module);
|
// self.order_module = OrderModule::WorstWordsSRS(module);
|
||||||
index
|
// index
|
||||||
}
|
// }
|
||||||
};
|
};
|
||||||
|
|
||||||
self.current_word_index = Some(index);
|
self.current_word_index = Some(index);
|
||||||
@@ -417,10 +417,10 @@ impl CardSet {
|
|||||||
module.open(status, index, word.clone());
|
module.open(status, index, word.clone());
|
||||||
self.order_module = OrderModule::RandomSRS(module);
|
self.order_module = OrderModule::RandomSRS(module);
|
||||||
}
|
}
|
||||||
OrderModule::WorstWordsSRS(mut module) => {
|
// OrderModule::WorstWordsSRS(mut module) => {
|
||||||
module.open(status, index, word.clone());
|
// module.open(status, index, word.clone());
|
||||||
self.order_module = OrderModule::WorstWordsSRS(module);
|
// self.order_module = OrderModule::WorstWordsSRS(module);
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
update_stat_score(word, &self.state.lock().unwrap().connection)
|
update_stat_score(word, &self.state.lock().unwrap().connection)
|
||||||
}
|
}
|
||||||
@@ -431,9 +431,9 @@ impl CardSet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Copy, Eq)]
|
#[derive(Clone, PartialEq, Copy, Eq)]
|
||||||
pub(crate) enum SetOrderMode {
|
pub enum SetOrderMode {
|
||||||
Default,
|
Default,
|
||||||
TrainWorstFirst,
|
// TrainWorstFirst,
|
||||||
FullRandom,
|
FullRandom,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -441,7 +441,7 @@ pub(crate) enum SetOrderMode {
|
|||||||
enum OrderModule {
|
enum OrderModule {
|
||||||
SemiRandomSRS(SemiRandomSRSModule),
|
SemiRandomSRS(SemiRandomSRSModule),
|
||||||
RandomSRS(RandomSRSModule),
|
RandomSRS(RandomSRSModule),
|
||||||
WorstWordsSRS(WorstWordsSRSModule),
|
// WorstWordsSRS(WorstWordsSRSModule),
|
||||||
}
|
}
|
||||||
|
|
||||||
trait SRSModule {
|
trait SRSModule {
|
||||||
@@ -452,35 +452,35 @@ trait SRSModule {
|
|||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct RandomSRSModule {
|
struct RandomSRSModule {
|
||||||
backet: Vec<usize>,
|
basket: Vec<usize>,
|
||||||
initializated: bool,
|
initialized: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RandomSRSModule {
|
impl RandomSRSModule {
|
||||||
fn new() -> RandomSRSModule {
|
fn new() -> RandomSRSModule {
|
||||||
Self{
|
Self{
|
||||||
backet: vec![],
|
basket: vec![],
|
||||||
initializated: false,
|
initialized: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SRSModule for RandomSRSModule {
|
impl SRSModule for RandomSRSModule {
|
||||||
fn next(&mut self, set: &mut CardSet) -> usize {
|
fn next(&mut self, set: &mut CardSet) -> usize {
|
||||||
if self.backet.is_empty() {
|
if self.basket.is_empty() {
|
||||||
self.backet = (0..set.words.len()).collect::<Vec<usize>>();
|
self.basket = (0..set.words.len()).collect::<Vec<usize>>();
|
||||||
self.backet.shuffle(&mut rand::rng())
|
self.basket.shuffle(&mut rand::rng())
|
||||||
}
|
}
|
||||||
|
|
||||||
self.backet.pop().unwrap()
|
self.basket.pop().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn open(&mut self, _: WordOpenMode, _: usize, _: CardStatistics) {}
|
fn open(&mut self, _: WordOpenMode, _: usize, _: CardStatistics) {}
|
||||||
|
|
||||||
fn init(&mut self, set: &mut CardSet) {
|
fn init(&mut self, set: &mut CardSet) {
|
||||||
self.initializated = true;
|
self.initialized = true;
|
||||||
self.backet = (0..set.words.len()).collect::<Vec<usize>>();
|
self.basket = (0..set.words.len()).collect::<Vec<usize>>();
|
||||||
self.backet.shuffle(&mut rand::rng())
|
self.basket.shuffle(&mut rand::rng())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -489,7 +489,7 @@ struct SemiRandomSRSModule {
|
|||||||
history: Vec<usize>,
|
history: Vec<usize>,
|
||||||
last_weights: WeightedIndex<f32>,
|
last_weights: WeightedIndex<f32>,
|
||||||
generator: ThreadRng,
|
generator: ThreadRng,
|
||||||
initializated: bool,
|
initialized: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SemiRandomSRSModule {
|
impl SemiRandomSRSModule {
|
||||||
@@ -498,7 +498,7 @@ impl SemiRandomSRSModule {
|
|||||||
history: vec![],
|
history: vec![],
|
||||||
last_weights: WeightedIndex::new([1.0]).unwrap(),
|
last_weights: WeightedIndex::new([1.0]).unwrap(),
|
||||||
generator: rng(),
|
generator: rng(),
|
||||||
initializated: false,
|
initialized: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -519,7 +519,7 @@ impl SRSModule for SemiRandomSRSModule {
|
|||||||
index
|
index
|
||||||
}
|
}
|
||||||
|
|
||||||
fn open(&mut self, status: WordOpenMode, index: usize, word: CardStatistics) {
|
fn open(&mut self, _: WordOpenMode, index: usize, word: CardStatistics) {
|
||||||
let new_weight = (100.0 / word.calculated_score()).powf(2.0);
|
let new_weight = (100.0 / word.calculated_score()).powf(2.0);
|
||||||
self.last_weights
|
self.last_weights
|
||||||
.update_weights(&[(index, &new_weight)])
|
.update_weights(&[(index, &new_weight)])
|
||||||
@@ -527,7 +527,7 @@ impl SRSModule for SemiRandomSRSModule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn init(&mut self, set: &mut CardSet) {
|
fn init(&mut self, set: &mut CardSet) {
|
||||||
self.initializated = true;
|
self.initialized = true;
|
||||||
let weights = set
|
let weights = set
|
||||||
.set
|
.set
|
||||||
.iter()
|
.iter()
|
||||||
@@ -546,29 +546,29 @@ impl SemiRandomSRSModule {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
// #[derive(Clone)]
|
||||||
struct WorstWordsSRSModule {
|
// struct WorstWordsSRSModule {
|
||||||
initializated: bool,
|
// initializated: bool,
|
||||||
}
|
// }
|
||||||
|
|
||||||
impl SRSModule for WorstWordsSRSModule {
|
// impl SRSModule for WorstWordsSRSModule {
|
||||||
fn next(&mut self, set: &mut CardSet) -> usize {
|
// fn next(&mut self, _: &mut CardSet) -> usize {
|
||||||
todo!()
|
// todo!()
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
fn open(&mut self, status: WordOpenMode, index: usize, updated_word: CardStatistics) {
|
// fn open(&mut self, _: WordOpenMode, _: usize, _: CardStatistics) {
|
||||||
todo!()
|
// todo!()
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
fn init(&mut self, set: &mut CardSet) {
|
// fn init(&mut self, _: &mut CardSet) {
|
||||||
todo!()
|
// todo!()
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
impl WorstWordsSRSModule {
|
// impl WorstWordsSRSModule {
|
||||||
fn new() -> WorstWordsSRSModule {
|
// fn new() -> WorstWordsSRSModule {
|
||||||
WorstWordsSRSModule {
|
// WorstWordsSRSModule {
|
||||||
initializated: false,
|
// initializated: false,
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|||||||
+2
-1
@@ -14,7 +14,7 @@ mod writing;
|
|||||||
|
|
||||||
use crate::data_provider::card_sets::load_sets;
|
use crate::data_provider::card_sets::load_sets;
|
||||||
use crate::data_provider::settings::get_setting;
|
use crate::data_provider::settings::get_setting;
|
||||||
use crate::data_provider::words::{create_db, load_word_groups, load_words};
|
use crate::data_provider::words::{ load_word_groups, load_words};
|
||||||
use crate::dictionary::{app_data_dir, DictionaryMessage, DictionaryState};
|
use crate::dictionary::{app_data_dir, DictionaryMessage, DictionaryState};
|
||||||
use crate::dictionary_test::{DictionaryQuizMessage, DictionaryQuizState};
|
use crate::dictionary_test::{DictionaryQuizMessage, DictionaryQuizState};
|
||||||
use crate::lang::{WordData, WordGroup};
|
use crate::lang::{WordData, WordGroup};
|
||||||
@@ -37,6 +37,7 @@ use iced::{keyboard, Element, Subscription};
|
|||||||
use iced::{Font, Task};
|
use iced::{Font, Task};
|
||||||
use rusqlite::Connection;
|
use rusqlite::Connection;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
use crate::data_provider::sqlite::create_db;
|
||||||
|
|
||||||
const DEFAULT_SPACING: f32 = 10.0;
|
const DEFAULT_SPACING: f32 = 10.0;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user