loading inner collections
This commit is contained in:
@@ -0,0 +1,48 @@
|
|||||||
|
use rusqlite::Connection;
|
||||||
|
use serde_json::Value;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct ImportData(Vec<ImportGroup>);
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct ImportGroup {
|
||||||
|
id: u64,
|
||||||
|
name: String,
|
||||||
|
fields: Vec<String>,
|
||||||
|
mapping: HashMap<String, String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct ImportNote {
|
||||||
|
name: String,
|
||||||
|
tags: String,
|
||||||
|
fields: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_groups(connection: &Connection) -> ImportData {
|
||||||
|
let json_models: String = connection
|
||||||
|
.query_one("select models from col", (), |row| row.get(0))
|
||||||
|
.unwrap();
|
||||||
|
let raw: Value = serde_json::from_str(json_models.as_str()).unwrap();
|
||||||
|
let sets = raw.as_object().unwrap();
|
||||||
|
let mut total_data = ImportData(vec![]);
|
||||||
|
|
||||||
|
for (_, collection) in sets {
|
||||||
|
let fields = collection["flds"]
|
||||||
|
.as_array()
|
||||||
|
.unwrap()
|
||||||
|
.iter()
|
||||||
|
.map(|x| x["name"].as_str().unwrap().to_string())
|
||||||
|
.collect();
|
||||||
|
let group = ImportGroup {
|
||||||
|
id: collection["id"].as_u64().unwrap(),
|
||||||
|
name: collection["name"].as_str().unwrap().to_string(),
|
||||||
|
fields,
|
||||||
|
mapping: Default::default(),
|
||||||
|
};
|
||||||
|
println!("{:?}", group);
|
||||||
|
total_data.0.push(group);
|
||||||
|
}
|
||||||
|
total_data
|
||||||
|
}
|
||||||
@@ -6,3 +6,4 @@ pub(crate) mod sqlite;
|
|||||||
pub(crate) mod voice;
|
pub(crate) mod voice;
|
||||||
pub(crate) mod words;
|
pub(crate) mod words;
|
||||||
pub(crate) mod web_api;
|
pub(crate) mod web_api;
|
||||||
|
pub(crate) mod import;
|
||||||
|
|||||||
+1
-1
@@ -264,7 +264,7 @@ impl NavigatedPage<DictionaryMessage> for DictionaryState {
|
|||||||
row![horizontal().width(8), self.words_list(),],
|
row![horizontal().width(8), self.words_list(),],
|
||||||
row![button("Добавить слово").style(jl_button).on_press(NewWord),
|
row![button("Добавить слово").style(jl_button).on_press(NewWord),
|
||||||
horizontal().width(Fill),
|
horizontal().width(Fill),
|
||||||
button("Импорт").style(jl_button).on_press(ToImport),
|
button("Импорт").style(text).on_press(ToImport),
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
.spacing(5),
|
.spacing(5),
|
||||||
|
|||||||
+134
-14
@@ -1,44 +1,164 @@
|
|||||||
use std::sync::{Arc, Mutex};
|
use crate::data_provider::import::{load_groups, ImportData};
|
||||||
use iced::{Element, Task};
|
use crate::dictionary::app_data_dir;
|
||||||
use iced::widget::scrollable;
|
use crate::import::ImportMessage::*;
|
||||||
use crate::navigation::{NavigatedPage, Page, RootMessage};
|
use crate::navigation::{NavigatedPage, Page, RootMessage};
|
||||||
use crate::styling::*;
|
use crate::styling::*;
|
||||||
use iced::widget::{column, row, button, text };
|
|
||||||
use crate::AppState;
|
use crate::AppState;
|
||||||
use crate::import::ImportMessage::*;
|
use iced::widget::scrollable;
|
||||||
|
use iced::widget::{button, column, row, text};
|
||||||
|
use iced::{Element, Task};
|
||||||
|
use iced_core::Alignment::Center;
|
||||||
|
use rfd::AsyncFileDialog;
|
||||||
|
use rusqlite::Connection;
|
||||||
|
use std::fs::{File, OpenOptions};
|
||||||
|
use std::io::BufReader;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
use tokio::task::spawn_blocking;
|
||||||
|
use zip::ZipArchive;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct ImportState {
|
pub struct ImportState {
|
||||||
state: Arc<Mutex<AppState>>
|
state: Arc<Mutex<AppState>>,
|
||||||
|
path: Option<PathBuf>,
|
||||||
|
import_data: Option<ImportData>,
|
||||||
|
selected_index: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub enum ImportMessage {
|
pub enum ImportMessage {
|
||||||
Back
|
Back,
|
||||||
|
SelectFile,
|
||||||
|
UpdateFile(PathBuf),
|
||||||
|
UpdateImport(ImportData),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NavigatedPage<ImportMessage> for ImportState {
|
impl NavigatedPage<ImportMessage> for ImportState {
|
||||||
fn navigate(&self, message: &ImportMessage) -> Option<Page> {
|
fn navigate(&self, message: &ImportMessage) -> Option<Page> {
|
||||||
if let Back = message {
|
if let Back = message {
|
||||||
return Some(Page::PreviousPage)
|
return Some(Page::PreviousPage);
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn navigated(&mut self) {
|
fn navigated(&mut self) {}
|
||||||
}
|
|
||||||
|
|
||||||
fn update(&mut self, message: ImportMessage) -> Task<RootMessage> {
|
fn update(&mut self, message: ImportMessage) -> Task<RootMessage> {
|
||||||
|
match message {
|
||||||
|
Back => {}
|
||||||
|
UpdateFile(path) => {
|
||||||
|
self.path = Some(path);
|
||||||
|
return self.load_package();
|
||||||
|
}
|
||||||
|
SelectFile => return Self::select_import_file(),
|
||||||
|
UpdateImport(import) => {
|
||||||
|
self.import_data = Some(import);
|
||||||
|
}
|
||||||
|
}
|
||||||
Task::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view(&self) -> Element<'_, ImportMessage> {
|
fn view(&self) -> Element<'_, ImportMessage> {
|
||||||
back_overlay(scrollable(column![]).into(), Back)
|
back_overlay(
|
||||||
|
scrollable(
|
||||||
|
column![
|
||||||
|
row![
|
||||||
|
button("Выбрать файл").style(jl_button).on_press(SelectFile),
|
||||||
|
text!("{}", {
|
||||||
|
if let Some(path) = &self.path {
|
||||||
|
path.to_string_lossy().to_string()
|
||||||
|
} else {
|
||||||
|
"Файл не выбран".to_string()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
]
|
||||||
|
.align_y(Center)
|
||||||
|
.spacing(DEFAULT_SPACING)
|
||||||
|
]
|
||||||
|
.spacing(DEFAULT_SPACING),
|
||||||
|
)
|
||||||
|
.into(),
|
||||||
|
Back,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl ImportState {
|
impl ImportState {
|
||||||
pub fn new(state: Arc<Mutex<AppState>>) -> ImportState {
|
pub fn new(state: Arc<Mutex<AppState>>) -> ImportState {
|
||||||
ImportState{
|
ImportState {
|
||||||
state
|
state,
|
||||||
|
path: None,
|
||||||
|
import_data: None,
|
||||||
|
selected_index: 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
fn select_import_file() -> Task<RootMessage> {
|
||||||
|
Task::perform(
|
||||||
|
async {
|
||||||
|
let file = AsyncFileDialog::new()
|
||||||
|
.add_filter("Anki", &["apkg"])
|
||||||
|
.pick_file()
|
||||||
|
.await;
|
||||||
|
if let Some(file) = file {
|
||||||
|
return Some(file.path().into());
|
||||||
|
}
|
||||||
|
None
|
||||||
|
},
|
||||||
|
|result| {
|
||||||
|
if let Some(path) = result {
|
||||||
|
RootMessage::Import(UpdateFile(path))
|
||||||
|
} else {
|
||||||
|
RootMessage::None
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_package(&self) -> Task<RootMessage> {
|
||||||
|
let path = self.path.clone().unwrap();
|
||||||
|
Task::perform(
|
||||||
|
async {
|
||||||
|
spawn_blocking(move || {
|
||||||
|
Self::extract_import_file(path)?;
|
||||||
|
let data = Self::read_import_file()?;
|
||||||
|
return Ok(data);
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
},
|
||||||
|
|result: Result<ImportData, ()>| {
|
||||||
|
if let Ok(import) = result {
|
||||||
|
RootMessage::Import(UpdateImport(import))
|
||||||
|
} else {
|
||||||
|
RootMessage::None
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extract_import_file(path: PathBuf) -> Result<(), ()> {
|
||||||
|
let file = File::open(path).map_err(|_| ())?;
|
||||||
|
let reader = BufReader::new(file);
|
||||||
|
let mut archive = ZipArchive::new(reader).map_err(|_| ())?;
|
||||||
|
let db_file = archive.by_name("collection.anki2");
|
||||||
|
if let Ok(mut file) = db_file {
|
||||||
|
let temp_file_path = app_data_dir().join("import");
|
||||||
|
let mut temp_file = OpenOptions::new()
|
||||||
|
.write(true)
|
||||||
|
.create(true)
|
||||||
|
.truncate(true)
|
||||||
|
.open(&temp_file_path)
|
||||||
|
.map_err(|_| ())?;
|
||||||
|
std::io::copy(&mut file, &mut temp_file).map_err(|_| ())?;
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn read_import_file() -> Result<ImportData, ()> {
|
||||||
|
let temp_file_path = app_data_dir().join("import");
|
||||||
|
let connection = Connection::open(&temp_file_path).map_err(|_| ())?;
|
||||||
|
let data = load_groups(&connection);
|
||||||
|
Ok(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user