fixes
This commit is contained in:
154
src/main.rs
154
src/main.rs
@@ -1,32 +1,44 @@
|
||||
mod app;
|
||||
mod telegram;
|
||||
mod input;
|
||||
mod tdlib;
|
||||
mod ui;
|
||||
mod utils;
|
||||
|
||||
use anyhow::Result;
|
||||
use crossterm::{
|
||||
event::{self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode},
|
||||
event::{self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode, KeyModifiers},
|
||||
execute,
|
||||
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
|
||||
};
|
||||
use ratatui::{
|
||||
backend::CrosstermBackend,
|
||||
Terminal,
|
||||
};
|
||||
use ratatui::{backend::CrosstermBackend, Terminal};
|
||||
use std::io;
|
||||
use std::time::Duration;
|
||||
use tdlib_rs::enums::Update;
|
||||
|
||||
use app::App;
|
||||
use app::{App, AppScreen};
|
||||
use input::{handle_auth_input, handle_main_input};
|
||||
use tdlib::client::AuthState;
|
||||
use utils::disable_tdlib_logs;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
async fn main() -> Result<(), io::Error> {
|
||||
// Загружаем переменные окружения из .env
|
||||
let _ = dotenvy::dotenv();
|
||||
|
||||
// Отключаем логи TDLib ДО создания клиента
|
||||
disable_tdlib_logs();
|
||||
|
||||
// Setup terminal
|
||||
enable_raw_mode()?;
|
||||
let mut stdout = io::stdout();
|
||||
execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?;
|
||||
let backend = CrosstermBackend::new(stdout);
|
||||
let mut terminal = Terminal::new(backend)?;
|
||||
|
||||
// Create app state
|
||||
let mut app = App::new();
|
||||
let res = run_app(&mut terminal, &mut app).await;
|
||||
|
||||
// Restore terminal
|
||||
disable_raw_mode()?;
|
||||
execute!(
|
||||
terminal.backend_mut(),
|
||||
@@ -45,24 +57,120 @@ async fn main() -> Result<()> {
|
||||
async fn run_app<B: ratatui::backend::Backend>(
|
||||
terminal: &mut Terminal<B>,
|
||||
app: &mut App,
|
||||
) -> Result<()> {
|
||||
loop {
|
||||
terminal.draw(|f| ui::draw(f, app))?;
|
||||
) -> io::Result<()> {
|
||||
// Канал для передачи updates из polling задачи в main loop
|
||||
let (update_tx, mut update_rx) = tokio::sync::mpsc::unbounded_channel::<Update>();
|
||||
|
||||
if event::poll(std::time::Duration::from_millis(100))? {
|
||||
// Запускаем polling TDLib receive() в отдельной задаче
|
||||
tokio::spawn(async move {
|
||||
loop {
|
||||
// receive() блокирующий, поэтому запускаем в blocking thread
|
||||
let result = tokio::task::spawn_blocking(|| tdlib_rs::receive()).await;
|
||||
if let Ok(Some((update, _client_id))) = result {
|
||||
let _ = update_tx.send(update);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Запускаем инициализацию TDLib в фоне
|
||||
let client_id = app.td_client.client_id();
|
||||
let api_id = app.td_client.api_id;
|
||||
let api_hash = app.td_client.api_hash.clone();
|
||||
|
||||
tokio::spawn(async move {
|
||||
let _ = tdlib_rs::functions::set_tdlib_parameters(
|
||||
false, // use_test_dc
|
||||
"tdlib_data".to_string(), // database_directory
|
||||
"".to_string(), // files_directory
|
||||
"".to_string(), // database_encryption_key
|
||||
true, // use_file_database
|
||||
true, // use_chat_info_database
|
||||
true, // use_message_database
|
||||
false, // use_secret_chats
|
||||
api_id,
|
||||
api_hash,
|
||||
"en".to_string(), // system_language_code
|
||||
"Desktop".to_string(), // device_model
|
||||
"".to_string(), // system_version
|
||||
env!("CARGO_PKG_VERSION").to_string(), // application_version
|
||||
client_id,
|
||||
)
|
||||
.await;
|
||||
});
|
||||
|
||||
loop {
|
||||
// Обрабатываем updates от TDLib из канала (неблокирующе)
|
||||
while let Ok(update) = update_rx.try_recv() {
|
||||
app.td_client.handle_update(update);
|
||||
}
|
||||
|
||||
// Обновляем состояние экрана на основе auth_state
|
||||
update_screen_state(app).await;
|
||||
|
||||
terminal.draw(|f| ui::render(f, app))?;
|
||||
|
||||
// Используем poll для неблокирующего чтения событий
|
||||
if event::poll(Duration::from_millis(100))? {
|
||||
if let Event::Key(key) = event::read()? {
|
||||
match key.code {
|
||||
KeyCode::Char('q') | KeyCode::Esc => return Ok(()),
|
||||
KeyCode::Char('1') => app.select_tab(0),
|
||||
KeyCode::Char('2') => app.select_tab(1),
|
||||
KeyCode::Char('3') => app.select_tab(2),
|
||||
KeyCode::Char('4') => app.select_tab(3),
|
||||
KeyCode::Up => app.previous_chat(),
|
||||
KeyCode::Down => app.next_chat(),
|
||||
KeyCode::Enter => app.open_chat(),
|
||||
_ => {}
|
||||
// Global quit command
|
||||
if key.code == KeyCode::Char('c') && key.modifiers.contains(KeyModifiers::CONTROL) {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
match app.screen {
|
||||
AppScreen::Loading => {
|
||||
// В состоянии загрузки игнорируем ввод
|
||||
}
|
||||
AppScreen::Auth => handle_auth_input(app, key.code).await,
|
||||
AppScreen::Main => handle_main_input(app, key).await,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn update_screen_state(app: &mut App) {
|
||||
use tokio::time::timeout;
|
||||
|
||||
let prev_screen = app.screen.clone();
|
||||
|
||||
match &app.td_client.auth_state {
|
||||
AuthState::WaitTdlibParameters => {
|
||||
app.screen = AppScreen::Loading;
|
||||
app.status_message = Some("Инициализация TDLib...".to_string());
|
||||
}
|
||||
AuthState::WaitPhoneNumber | AuthState::WaitCode | AuthState::WaitPassword => {
|
||||
app.screen = AppScreen::Auth;
|
||||
app.is_loading = false;
|
||||
}
|
||||
AuthState::Ready => {
|
||||
if prev_screen != AppScreen::Main {
|
||||
app.screen = AppScreen::Main;
|
||||
app.is_loading = true;
|
||||
app.status_message = Some("Загрузка чатов...".to_string());
|
||||
|
||||
// Запрашиваем загрузку чатов с таймаутом
|
||||
let _ = timeout(Duration::from_secs(5), app.td_client.load_chats(50)).await;
|
||||
}
|
||||
|
||||
// Синхронизируем чаты из td_client в app
|
||||
if !app.td_client.chats.is_empty() {
|
||||
app.chats = app.td_client.chats.clone();
|
||||
if app.chat_list_state.selected().is_none() && !app.chats.is_empty() {
|
||||
app.chat_list_state.select(Some(0));
|
||||
}
|
||||
// Убираем статус загрузки когда чаты появились
|
||||
if app.is_loading {
|
||||
app.is_loading = false;
|
||||
app.status_message = None;
|
||||
}
|
||||
}
|
||||
}
|
||||
AuthState::Closed => {
|
||||
app.status_message = Some("Соединение закрыто".to_string());
|
||||
}
|
||||
AuthState::Error(e) => {
|
||||
app.error_message = Some(e.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user