Updated word display #19

Merged
micialware merged 13 commits from updated-word-display into master 2026-09-13 17:42:58 +03:00
4 changed files with 121 additions and 81 deletions
Showing only changes of commit 0de809fcce - Show all commits

No files matched your search

+16 -3
View File
@@ -1,9 +1,9 @@
use litemap::LiteMap;
use crate::data::entities::WordData;
use crate::data::repositories::{DataRepository, DataRepositoryInner};
use crate::data::Id;
use crate::data_provider::{SqliteDbLayer, TableAccessQuerySet};
use litemap::LiteMap;
use rusqlite::{Error, Params, Row};
use crate::data::{Id, SmallId};
pub type WordRepository = DataRepository<WordData, WordDataLayer>;
pub type WordRepositoryInner = DataRepositoryInner<WordData, WordDataLayer>;
@@ -61,7 +61,7 @@ impl TableAccessQuerySet<WordData> for WordQuerySet {
}
fn additional_to_string(map: &LiteMap<Id, String>) -> String {
let mut parts = vec![];
let mut parts = Vec::with_capacity(map.len() * 2);
for (id, value) in map {
parts.push(id.to_string());
parts.push(value.clone());
@@ -69,7 +69,20 @@ fn additional_to_string(map: &LiteMap<Id, String>) -> String {
parts.join("")
}
fn additional_from_string_temp(data: String) -> LiteMap<Id, String> {
let pre_map : LiteMap<String, String> = serde_json::from_str(data.as_str()).unwrap();
LiteMap::from(pre_map.iter().map(|(k, v)| (match k.as_str() {
"reading" => Id(1),
"description" => Id(2),
"context" => Id(3),
&_ => Id(0) }, v.to_string())).collect())
}
fn additional_from_string(data: String) -> LiteMap<Id, String> {
if data.is_empty() {
return LiteMap::new()
}
let parts = data.split('').collect::<Vec<&str>>();
let chunks = parts.chunks(2).collect::<Vec<&[&str]>>();
let mut map = LiteMap::with_capacity(parts.len());
+42 -4
View File
@@ -1,16 +1,17 @@
use crate::app::AppState;
use crate::data::entities::WordData;
use crate::data::Id;
use crate::data::entities::WordGroup;
use crate::data::entities::{CustomField, WordData};
use crate::data::repositories::{BatchedRepository, Repository};
use crate::data_provider::import::{ImportData, ImportGroup, get_words_of_group, load_groups};
use crate::fs::*;
use crate::jl_button;
use crate::navigation::{NavigatedPage, Page, RootMessage};
use crate::notification::NotificationData::OpenFileError;
use crate::notification::{MaybeError, NotificationData};
use crate::pages::import::ImportMessage::*;
use crate::push_error;
use crate::styling::*;
use crate::{jl_button, push_error_task};
use iced::widget::button::danger;
use iced::widget::container::success;
use iced::widget::{
@@ -25,6 +26,7 @@ use log::info;
use parking_lot::Mutex;
use rfd::AsyncFileDialog;
use rusqlite::Connection;
use std::collections::HashMap;
use std::fs::{File, OpenOptions};
use std::io::BufReader;
use std::path::PathBuf;
@@ -428,7 +430,19 @@ impl ImportState {
let separator = self.separator.clone();
let skip_empty = self.skip_empty;
let group = self.import_data.as_ref().unwrap().0[self.selected_index].clone();
let map_indices = Self::get_mapping_indices(&group);
let progress = self.progress.clone().unwrap();
if let Err(err) = Self::ensure_fields(&state, &map_indices) {
return push_error_task!(err);
}
let fields: HashMap<String, Id> = HashMap::from_iter(
state
.custom_fields
.read()
.iter()
.map(|f| (f.identifier.clone(), f.id)),
);
info!("{}", group.name);
Task::perform(
async move {
@@ -439,7 +453,6 @@ impl ImportState {
let import_list = get_words_of_group(&connection, group.id)?;
let mut words_list = Vec::with_capacity(import_list.len());
let map_indices = Self::get_mapping_indices(&group);
let group_handle;
{
let group_entity = WordGroup {
@@ -474,7 +487,7 @@ impl ImportState {
word.tags = collected_string;
}
&_ => {
word.additional.insert((*dest).clone(), collected_string);
word.additional.insert(fields[dest], collected_string);
}
}
}
@@ -554,4 +567,29 @@ impl ImportState {
|_| RootMessage::Import(NextProgress),
)
}
fn ensure_fields(
state: &AppState,
import_group: &Vec<(String, Vec<usize>)>,
) -> Result<(), NotificationData> {
let mut fields_repo = state.custom_fields.write();
let mut current_fields: Vec<String> = fields_repo
.iter()
.map(|field| field.identifier.clone())
.collect();
current_fields.append(&mut vec!["key".to_string(), "value".to_string(), "tags".to_string()]);
for (field, _) in import_group {
if current_fields.contains(field) {
continue;
}
fields_repo.create_now(CustomField {
id: Default::default(),
name: field.clone(),
identifier: field.clone(),
})?;
}
Ok(())
}
}
+3 -3
View File
@@ -262,19 +262,19 @@ impl RepetitionState {
}
fn draw_reading(&self, word: &WordData) -> Element<'_, RepetitionMessage> {
match word.additional.get("reading") {
match word.additional.get(&Id(1)) {
None => space().into(),
Some(reading) => text!("{}", reading).size(24).into(),
}
}
fn draw_context(&self, word: &WordData) -> Element<'_, RepetitionMessage> {
match word.additional.get("context") {
match word.additional.get(&Id(3)) {
None => space().into(),
Some(context) => text!("{}", context).size(24).into(),
}
}
fn draw_description(&self, word: &WordData) -> Element<'_, RepetitionMessage> {
match word.additional.get("description") {
match word.additional.get(&Id(2)) {
None => space().into(),
Some(context) => text!("{}", context).size(24).into(),
}
+60 -71
View File
@@ -1,5 +1,6 @@
use crate::app::AppState;
use crate::data::entities::{EntityHandle, WordData};
use crate::data::Id;
use crate::data::entities::{CustomField, EntityHandle, WordData};
use crate::data::repositories::Repository;
use crate::pages::word::WordMessage::*;
use crate::styling::*;
@@ -7,15 +8,17 @@ use iced::widget::button::danger;
use iced::widget::space::horizontal;
use iced::widget::{button, column, row, rule, scrollable, text, text_input};
use iced::{Element, Fill};
use iced_core::Padding;
pub struct WordEditor<Message> {
state: AppState,
handle: EntityHandle<WordData>,
on_delete: Option<Message>,
on_edit: Option<Message>,
fields: Vec<CustomField>,
}
impl<Message> WordEditor<Message> {
impl<Message> WordEditor<Message> {
pub(crate) fn update(&mut self, message: WordMessage) -> Option<Message> {
let dictionary = &mut self.state.dictionary.write();
let word = dictionary.get_mut(&mut self.handle).unwrap();
@@ -37,7 +40,7 @@ impl<Message> WordEditor<Message> {
word.additional.insert(key, "".to_string());
}
RemoveAdditional(key) => {
word.additional.remove(key.as_str());
word.additional.remove(&key);
}
}
self.on_edit.take()
@@ -45,36 +48,25 @@ impl<Message> WordEditor<Message> {
pub(crate) fn view(&self) -> Element<'_, WordMessage> {
let mut fast_add = row![];
let word = self.state.dictionary.read().get_static(self.handle).unwrap();
if !word.additional.contains_key("reading") {
fast_add = fast_add.push(
button("Чтение")
.style(button::text)
.on_press(AddAdditional("reading".to_string())),
);
}
if !word.additional.contains_key("description") {
fast_add = fast_add.push(
button("Описание")
.style(button::text)
.on_press(AddAdditional("description".to_string())),
);
}
if !word.additional.contains_key("context") {
fast_add = fast_add.push(
button("В контексте")
.style(button::text)
.on_press(AddAdditional("context".to_string())),
);
let word = self
.state
.dictionary
.read()
.get_static(self.handle)
.unwrap();
for field in &self.fields {
if !word.additional.contains_key(&field.id) {
fast_add = fast_add.push(
button(field.name.as_str())
.style(button::text)
.on_press(AddAdditional(field.id)),
);
}
}
let mut col = iced::widget::column![
column![
text!("Ключ"),
text_input("key", &word.key).on_input(SetKey),
]
.spacing(QUARTER_SPACING),
column![text!("Ключ"), text_input("key", &word.key).on_input(SetKey),]
.spacing(QUARTER_SPACING),
column![
text!("Значение"),
text_input("value", &word.value).on_input(SetValue),
@@ -86,33 +78,46 @@ impl<Message> WordEditor<Message> {
]
.spacing(QUARTER_SPACING),
rule::horizontal(2),
scrollable(fast_add),
scrollable(fast_add.padding(Padding{
top: 0.0 , right: 0.0 , bottom: 4.0 , left: 0.0 , })).horizontal(),
];
for more in &word.additional {
col = col.push(self.get_view_for_more(more));
}
column![
col.spacing(DEFAULT_SPACING / 2.0).width(Fill).height(Fill),
row![
horizontal().width(Fill),
button("Удалить").style(danger).on_press(Delete),
]
.spacing(DEFAULT_SPACING)
column![
col.spacing(DEFAULT_SPACING / 2.0).width(Fill).height(Fill),
row![
horizontal().width(Fill),
button("Удалить").style(danger).on_press(Delete),
]
.spacing(DEFAULT_SPACING).into()
.spacing(DEFAULT_SPACING)
]
.spacing(DEFAULT_SPACING)
.into()
}
}
impl<Message> WordEditor<Message> {
pub fn new(handle: EntityHandle<WordData>, state: AppState) -> Self {
Self { state, handle, on_delete: None, on_edit: None }
let fields = state
.custom_fields
.read()
.iter()
.cloned()
.collect::<Vec<_>>();
Self {
state,
handle,
on_delete: None,
on_edit: None,
fields,
}
}
pub fn on_delete(mut self, message: Message) -> Self {
self.on_delete = Some(message);
self
@@ -124,38 +129,22 @@ impl<Message> WordEditor<Message> {
}
impl<Message> WordEditor<Message> {
fn get_view_for_more(&self, value: (&String, &String)) -> Element<'_, WordMessage> {
match value.0.as_str() {
"reading" => self.reading_field(value.1),
"description" => self.description_field(value.1),
"context" => self.context_field(value.1),
_ => self.additional_field(value.1, value.0.clone(), value.0.clone()),
fn get_view_for_more(&self, value: (&Id, &String)) -> Element<'_, WordMessage> {
let field = self.fields.iter().find(|f| f.id == *value.0).unwrap();
match value.0 {
_ => self.additional_field(value.1, field.name.as_str(), value.0.clone()),
}
}
fn reading_field(&self, value: &str) -> Element<'_, WordMessage> {
self.additional_field(value, "Чтение слова".to_string(), "reading".to_string())
}
fn description_field(&self, value: &str) -> Element<'_, WordMessage> {
self.additional_field(value, "Описание".to_string(), "description".to_string())
}
fn context_field(&self, value: &str) -> Element<'_, WordMessage> {
self.additional_field(value, "В контексте".to_string(), "context".to_string())
}
fn additional_field(&self, value: &str, name: String, id: String) -> Element<'_, WordMessage> {
fn additional_field(&self, value: &str, name: &str, id: Id) -> Element<'_, WordMessage> {
column![
text!("{}", name),
row![
text_input(id.clone().as_str(), value)
.on_input({
let value = id.clone();
move |string| SetAdditional(value.clone(), string)
})
text_input(name, value)
.on_input(move |string| SetAdditional(id, string))
.width(Fill),
button("-")
.on_press(RemoveAdditional(id.clone()))
.on_press(RemoveAdditional(id))
.style(danger),
]
.spacing(QUARTER_SPACING),
@@ -171,7 +160,7 @@ pub enum WordMessage {
SetTags(String),
SetKey(String),
SetValue(String),
AddAdditional(String),
RemoveAdditional(String),
SetAdditional(String, String),
AddAdditional(Id),
RemoveAdditional(Id),
SetAdditional(Id, String),
}