251 lines
8.4 KiB
Rust
251 lines
8.4 KiB
Rust
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};
|
|
use crate::styling::*;
|
|
use crate::sync::SyncMessage::*;
|
|
use crate::{AppState, RootMessage, fill_state};
|
|
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 std::sync::Arc;
|
|
use parking_lot::Mutex;
|
|
use std::time::Duration;
|
|
|
|
#[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| RootMessage::Sync(IdReceived(id)));
|
|
}
|
|
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;
|
|
}
|
|
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| {
|
|
eprintln!("Ошибка при checkpoint WAL: {e}");
|
|
});
|
|
}
|
|
}
|
|
|
|
#[inline]
|
|
fn validate_id(id: &str) -> bool {
|
|
id.len() == 24 && id.chars().all(|c| c.is_ascii_alphanumeric())
|
|
}
|