Splitting kana set
This commit is contained in:
1 parent
36e5693564
commit
c74a0eb311
25 files changed
+389
-354
No files matched your search
@@ -0,0 +1,258 @@
|
||||
use crate::data_provider::settings::{delete_settings, set_setting};
|
||||
use crate::data_provider::web_api::*;
|
||||
use crate::navigation::Page::PreviousPage;
|
||||
use crate::navigation::{NavigatedPage, Page, RootMessage};
|
||||
use crate::styling::*;
|
||||
use crate::pages::sync::SyncMessage::*;
|
||||
use iced::widget::button::danger;
|
||||
use iced::widget::container::rounded_box;
|
||||
use iced::widget::{button, column, container, progress_bar, row, space, text, toggler};
|
||||
use iced::{Center, Element, Fill, Font, Length, Task};
|
||||
use parking_lot::Mutex;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use log::error;
|
||||
use crate::app::{fill_state, AppState};
|
||||
use crate::notification::{NotificationRequest, NotificationData};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum SyncMessage {
|
||||
Back,
|
||||
CopyKey,
|
||||
KeyCopied,
|
||||
IdReceived(String),
|
||||
InitSync,
|
||||
GetKey,
|
||||
Send,
|
||||
GetLast,
|
||||
NextAnimation,
|
||||
NetworkFinished,
|
||||
Disable,
|
||||
DisableSync,
|
||||
SwitchAutoSync,
|
||||
}
|
||||
#[derive(Clone)]
|
||||
pub struct SyncState {
|
||||
state: Arc<Mutex<AppState>>,
|
||||
auto_fetch: bool,
|
||||
frozen: bool,
|
||||
progress: f32,
|
||||
}
|
||||
|
||||
impl NavigatedPage<SyncMessage> for SyncState {
|
||||
fn navigate(&mut self, message: &SyncMessage) -> Option<Page> {
|
||||
if let Back = message
|
||||
&& !self.frozen
|
||||
{
|
||||
Some(PreviousPage)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn navigated(&mut self) {}
|
||||
fn update(&mut self, message: SyncMessage) -> Task<RootMessage> {
|
||||
match message {
|
||||
Back => {}
|
||||
CopyKey => {
|
||||
let state = self.state.lock();
|
||||
let key = state.sync_data.key.clone().unwrap();
|
||||
return iced::clipboard::write(key)
|
||||
.map(|_val: String| RootMessage::Sync(KeyCopied));
|
||||
}
|
||||
InitSync => {
|
||||
return Task::perform(first_sync(), |id| {
|
||||
match id {
|
||||
Ok(id) => RootMessage::Sync(IdReceived(id)),
|
||||
Err(err) => RootMessage::PushNotification(NotificationRequest::Error(err))
|
||||
}
|
||||
});
|
||||
}
|
||||
GetKey => {
|
||||
return iced::clipboard::read()
|
||||
.map(|key| RootMessage::Sync(IdReceived(key.unwrap_or_else(String::new))));
|
||||
}
|
||||
KeyCopied => {}
|
||||
IdReceived(new_id) => {
|
||||
if !validate_id(&new_id) {
|
||||
return Task::none();
|
||||
}
|
||||
let mut state = self.state.lock();
|
||||
state.sync_data.key = Some(new_id.clone());
|
||||
set_setting("SYNC_KEY".to_string(), new_id, &state.connection);
|
||||
}
|
||||
Send => {
|
||||
self.prepare_to_db_interaction();
|
||||
|
||||
let id = self.state.lock().sync_data.key.clone().unwrap();
|
||||
let tasks = Task::batch([
|
||||
Task::perform(
|
||||
async { tokio::time::sleep(Duration::from_millis(200)).await },
|
||||
|_| RootMessage::Sync(NextAnimation),
|
||||
),
|
||||
Task::perform(send_data(id), |_| RootMessage::Sync(NetworkFinished)),
|
||||
]);
|
||||
|
||||
return tasks;
|
||||
}
|
||||
GetLast => {
|
||||
let id = self.state.lock().sync_data.key.clone().unwrap();
|
||||
let tasks = Task::batch([
|
||||
Task::perform(
|
||||
async { tokio::time::sleep(Duration::from_millis(200)).await },
|
||||
|_| RootMessage::Sync(NextAnimation),
|
||||
),
|
||||
Task::perform(load_data(id, false), |_| RootMessage::Sync(NetworkFinished)),
|
||||
]);
|
||||
|
||||
return tasks;
|
||||
}
|
||||
NextAnimation => {
|
||||
self.progress += 1.0;
|
||||
if self.progress > 5.0 {
|
||||
self.progress = 0.0;
|
||||
}
|
||||
if self.frozen {
|
||||
return Task::perform(
|
||||
async { tokio::time::sleep(Duration::from_millis(200)).await },
|
||||
|_| RootMessage::Sync(NextAnimation),
|
||||
);
|
||||
}
|
||||
}
|
||||
NetworkFinished => {
|
||||
self.frozen = false;
|
||||
let mut updated_state = AppState::new();
|
||||
fill_state(&mut updated_state);
|
||||
|
||||
let mut state = self.state.lock();
|
||||
state.sync_data = updated_state.sync_data;
|
||||
state.connection = updated_state.connection;
|
||||
state.decks = updated_state.decks;
|
||||
state.dictionary = updated_state.dictionary;
|
||||
state.word_groups = updated_state.word_groups;
|
||||
return Task::done(RootMessage::PushNotification(NotificationRequest::Info(NotificationData::DataLoaded)))
|
||||
}
|
||||
Disable => {}
|
||||
DisableSync => {
|
||||
let mut state = self.state.lock();
|
||||
state.sync_data.key = None;
|
||||
delete_settings("SYNC_KEY".to_string(), &state.connection);
|
||||
delete_settings("AUTO_WEB_FETCH".to_string(), &state.connection);
|
||||
}
|
||||
SwitchAutoSync => {
|
||||
self.auto_fetch = !self.auto_fetch;
|
||||
let mut state = self.state.lock();
|
||||
state.sync_data.auto_web_fetch = self.auto_fetch;
|
||||
set_setting(
|
||||
"AUTO_WEB_FETCH".to_string(),
|
||||
self.auto_fetch.to_string(),
|
||||
&state.connection,
|
||||
);
|
||||
}
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
|
||||
fn view(&self) -> Element<'_, SyncMessage> {
|
||||
back_overlay(
|
||||
row![space().width(Fill), self.sync_column(), space().width(Fill)]
|
||||
.spacing(DEFAULT_SPACING)
|
||||
.width(Fill)
|
||||
.into(),
|
||||
Back,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl SyncState {
|
||||
pub fn new(state: Arc<Mutex<AppState>>) -> SyncState {
|
||||
let auto_fetch;
|
||||
{
|
||||
auto_fetch = state.lock().sync_data.auto_web_fetch;
|
||||
}
|
||||
Self {
|
||||
auto_fetch,
|
||||
state,
|
||||
frozen: false,
|
||||
progress: 0.0,
|
||||
}
|
||||
}
|
||||
|
||||
fn sync_column(&self) -> Element<'_, SyncMessage> {
|
||||
let network_view: Element<'_, SyncMessage> = if self.frozen {
|
||||
progress_bar(0.0..=5.0, self.progress).into()
|
||||
} else {
|
||||
space().into()
|
||||
};
|
||||
{
|
||||
if let Some(key) = self.state.lock().sync_data.key.clone() {
|
||||
column![
|
||||
text!("Ваш ключ синхронизации"),
|
||||
container(
|
||||
container(
|
||||
text!("{}", key)
|
||||
.size(ACCENT_FONT_SIZE)
|
||||
.font(Font::MONOSPACE)
|
||||
)
|
||||
.padding(3)
|
||||
)
|
||||
.style(rounded_box),
|
||||
button("Скопировать в буфер обмена")
|
||||
.style(jl_button)
|
||||
.on_press(CopyKey)
|
||||
.width(Fill),
|
||||
row![
|
||||
button("↑ Отправить").style(jl_button).on_press(Send),
|
||||
space().width(Fill),
|
||||
button("↓ Скачать").style(jl_button).on_press(GetLast)
|
||||
]
|
||||
.spacing(DEFAULT_SPACING),
|
||||
toggler(self.auto_fetch)
|
||||
.label("Автоматическая синхронизация")
|
||||
.on_toggle(|_| SwitchAutoSync),
|
||||
container(network_view).width(Fill),
|
||||
button("Отключить синхронизацию")
|
||||
.style(danger)
|
||||
.on_press(DisableSync),
|
||||
]
|
||||
} else {
|
||||
column![
|
||||
button("Создать сохранение")
|
||||
.style(jl_button)
|
||||
.on_press(InitSync),
|
||||
button("Вставить ключ из буфера")
|
||||
.style(jl_button)
|
||||
.on_press(GetKey),
|
||||
]
|
||||
}
|
||||
}
|
||||
.spacing(DEFAULT_SPACING)
|
||||
.align_x(Center)
|
||||
.width(Length::Shrink)
|
||||
.into()
|
||||
}
|
||||
|
||||
/* fn app_updater(&self) -> Element<'_, SyncMessage> {
|
||||
column![].width(Fill).into()
|
||||
}*/
|
||||
|
||||
fn prepare_to_db_interaction(&mut self) {
|
||||
if self.frozen {
|
||||
return;
|
||||
}
|
||||
self.frozen = true;
|
||||
self.progress = 0.0;
|
||||
let state = self.state.lock();
|
||||
state
|
||||
.connection
|
||||
.query_row("PRAGMA wal_checkpoint(TRUNCATE)", [], |_| Ok(()))
|
||||
.unwrap_or_else(|e| {
|
||||
error!("Ошибка при checkpoint WAL: {e}");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn validate_id(id: &str) -> bool {
|
||||
id.len() == 24 && id.chars().all(|c| c.is_ascii_alphanumeric())
|
||||
}
|
||||
Reference in new issue
Block a user